Skip to content

Latest commit

 

History

History
476 lines (370 loc) · 10.3 KB

File metadata and controls

476 lines (370 loc) · 10.3 KB

CLI, Web UI, and API Plan

CLI principles

  • Minimal required arguments.
  • DB path comes from GHBB_DB or ./ghbb.db; no --db option.
  • Backup owner/org is derived from JSON; no --org option.
  • Human output by default.
  • --json output for agents.
  • Errors should be concise and actionable.

Use Typer + Rich.

CLI commands

ghbb import [BACKUP_ROOT]

Import a backup into the current database.

Examples:

ghbb import C:\CodeBlocks\ggml-org-backup\backup
ghbb import ../backup
ghbb import

Behavior:

  • Resolve DB via GHBB_DB or ./ghbb.db.
  • Resolve backup root as described in implementation-plan.md.
  • Rebuild imported tables for MVP.
  • Always import attachment metadata.
  • Never import attachment file contents.
  • Rebuild FTS after import.

Useful options:

--quiet       suppress progress output
--json        print import summary as JSON

Avoid extra options until needed.

Human summary example:

Imported C:\CodeBlocks\ggml-org-backup\backup into C:\CodeBlocks\github-backup-browser\ghbb.db

Repositories: 2
Items:
  issues:      8434
  pulls:       12028
  discussions: 3314
  releases:    5952
Comments:      123456
Attachments:   8647 metadata rows
Release assets: 12345
FTS docs:       98765
Warnings:       0

Counts above are illustrative except where documented in testing.md.

ghbb stats

Print database stats.

Examples:

ghbb stats
ghbb stats --json

Human output should include:

  • DB path;
  • backup root from last import;
  • last import status/time;
  • repositories;
  • item counts by repo and kind;
  • comment counts by kind;
  • attachment metadata rows;
  • release assets;
  • FTS docs.

JSON should have stable keys:

{
  "db_path": "...",
  "last_import": {
    "backup_root": "...",
    "started_at": "...",
    "finished_at": "...",
    "status": "ok"
  },
  "repositories": [
    {
      "full_name": "ggml-org/llama.cpp",
      "name": "llama.cpp",
      "items": {
        "issue": 7903,
        "pull": 11236,
        "discussion": 3177,
        "release": 5941
      }
    }
  ],
  "totals": {
    "repositories": 2,
    "items": 29728,
    "attachments": 8647
  }
}

ghbb search QUERY...

Search the FTS index.

Examples:

ghbb search "Fabrice Bellard"
ghbb search cuda graph memory leak
ghbb search "KV cache" --repo llama.cpp
ghbb search "ggml_backend_cuda" --repo ggml-org/llama.cpp --kind issue --state open
ghbb search "Metal" --author ggerganov --limit 10
ghbb search "quantization" --label enhancement
ghbb search "Fabrice Bellard" --json

Arguments/options:

QUERY...        one or more words; join with spaces
--repo TEXT     repo name or full name; e.g. llama.cpp or ggml-org/llama.cpp
--kind TEXT     issue, pull, discussion, release
--state TEXT    open, closed, published, prerelease, draft
--author TEXT   item author or hit/comment author
--label TEXT    item label
--limit INT     default 20
--offset INT    default 0
--json          agent-friendly JSON

Human output should be a Rich table:

score  repo       kind   key     state   title                              hit
0.12   llama.cpp  issue  12345   open    CUDA graph memory leak ...          comment by user123
0.19   ggml       issue  1       closed  Implement gpt2tc/nncp with ggml     item body

After the table, print a short snippet for each result, or use a compact multiline layout if snippets make the table too wide.

Each result must provide enough information for follow-up:

ghbb show llama.cpp issue 12345

JSON result shape:

{
  "query": "Fabrice Bellard",
  "limit": 20,
  "offset": 0,
  "results": [
    {
      "search_doc_id": 1,
      "item_id": 1,
      "comment_id": null,
      "repo": "ggml-org/ggml",
      "repo_name": "ggml",
      "kind": "issue",
      "item_key": "1",
      "number": 1,
      "tag_name": null,
      "state": "closed",
      "title": "Implement gpt2tc/nncp with ggml",
      "doc_type": "item",
      "hit_author": "...",
      "url": "https://github.com/ggml-org/ggml/issues/1",
      "snippet": "..."
    }
  ]
}

ghbb show REPO KIND KEY

Show an item/thread.

Examples:

ghbb show ggml issue 1
ghbb show ggml-org/ggml issue 1
ghbb show llama.cpp pull 10001
ghbb show ggml discussion 32
ghbb show llama.cpp release b1046
ghbb show ggml issue 1 --json

Arguments:

REPO      repo name or full name. If a short repo name is ambiguous, fail with choices.
KIND      issue, pull, discussion, release
KEY       issue/PR/discussion number or release tag

Human output should show:

  • repo/kind/key;
  • title;
  • URL;
  • state;
  • labels;
  • author;
  • created/updated/closed/published dates;
  • body;
  • comments/reviews/replies in chronological/import order;
  • attachment metadata;
  • release assets for releases.

For long bodies/comments, do not truncate by default. Agents need complete content. Add --limit-comments or --no-body later if needed.

JSON output should include:

{
  "item": {
    "id": 1,
    "repo": "ggml-org/ggml",
    "repo_name": "ggml",
    "kind": "issue",
    "item_key": "1",
    "number": 1,
    "tag_name": null,
    "title": "...",
    "body": "...",
    "body_text": "...",
    "state": "closed",
    "labels": ["enhancement"],
    "author": "...",
    "created_at": "...",
    "updated_at": "...",
    "url": "..."
  },
  "comments": [
    {
      "id": 10,
      "kind": "issue_comment",
      "author": "...",
      "body": "...",
      "created_at": "...",
      "url": "..."
    }
  ],
  "attachments": [
    {
      "original_filename": "...png",
      "content_type": "image/png",
      "size_bytes": 7326,
      "success": true,
      "original_url": "https://github.com/user-attachments/assets/...",
      "local_path": "repositories/ggml/issues/attachments/1010/...png"
    }
  ],
  "release_assets": []
}

ghbb repos

Optional but useful.

Examples:

ghbb repos
ghbb repos --json

Shows repos and counts by kind.

ghbb db-path

Small utility for agents and debugging.

ghbb db-path

Prints resolved DB path. This command can be hidden from README if desired, but it is useful during implementation.

ghbb serve

Run the local web app.

Examples:

ghbb serve
ghbb serve --host 127.0.0.1 --port 8765

Options:

--host TEXT     default 127.0.0.1
--port INT      default 8765
--reload        optional development convenience

Do not bind to 0.0.0.0 by default.

FTS query behavior

MVP should favor robustness over advanced syntax.

Suggested default query builder:

  1. Join QUERY... into one string.
  2. Preserve quoted phrases with shlex.split if possible.
  3. Escape embedded double quotes.
  4. Convert tokens to quoted FTS terms/phrases.
  5. Join with spaces, which FTS5 treats as AND.

Example:

user query:   KV cache
fts query:    "KV" "cache"

user query:   "Fabrice Bellard"
fts query:    "Fabrice Bellard"

If FTS raises a syntax error, return a clear error. Later add --raw-fts if advanced FTS syntax is needed.

Web UI routes

Use FastAPI with Jinja templates.

HTML pages

GET /                    home page with search box and repo summary
GET /search?q=...         search results with filters
GET /repos                repository list
GET /repos/{owner}/{repo} repo browse page
GET /items/{item_id}      item/thread page

Repo names can contain dots, so route parameters should allow llama.cpp. FastAPI path params handle this.

Alternative item routes can be added later:

GET /repos/{owner}/{repo}/issues/{number}
GET /repos/{owner}/{repo}/pulls/{number}
GET /repos/{owner}/{repo}/discussions/{number}
GET /repos/{owner}/{repo}/releases/{tag}

For MVP, /items/{item_id} is enough and avoids route escaping issues for release tags containing slashes.

JSON API endpoints

Agents should be able to use the web server without scraping HTML.

GET /api/stats
GET /api/repos
GET /api/search?q=...&repo=llama.cpp&kind=issue&state=open&limit=20&offset=0
GET /api/items/{item_id}

Response bodies should match CLI JSON as closely as possible.

Web UI design notes

Keep the UI dense, restrained, and documentation-like.

  • Neutral background.
  • One muted accent color.
  • No gradients, emoji icons, decorative blobs, or oversized cards.
  • Tables for repository and result listings.
  • Clear monospace treatment for repo names, tags, paths, and code identifiers.
  • Compact filters above search results.
  • Thread page should prioritize readability of Markdown/comment content.
  • Use local CSS only. Avoid CDN dependencies.

Suggested CSS direction:

:root {
  --bg: #f7f7f4;
  --surface: #ffffff;
  --text: #1d1f23;
  --muted: #626a73;
  --border: #d8dcd6;
  --accent: #355f7c;
  --accent-strong: #26495f;
  --code-bg: #f0f2ef;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
}

Layout:

  • base.html: top nav, main content width around 1180px, footer with DB path/import time.
  • index.html: prominent but compact search form, repo summary table.
  • search.html: filters + result list/table + snippets.
  • repo.html: counts and paginated item table.
  • item.html: metadata header + body + timeline.

Markdown rendering

Issue/PR/discussion content is untrusted.

Recommended helper:

from markdown_it import MarkdownIt
import bleach

md = MarkdownIt("commonmark", {"linkify": True, "breaks": False})

ALLOWED_TAGS = bleach.sanitizer.ALLOWED_TAGS | {
    "p", "pre", "code", "blockquote", "hr", "br",
    "h1", "h2", "h3", "h4", "h5", "h6",
    "table", "thead", "tbody", "tr", "th", "td",
    "ul", "ol", "li", "img"
}

ALLOWED_ATTRS = {
    **bleach.sanitizer.ALLOWED_ATTRIBUTES,
    "a": ["href", "title", "rel", "target"],
    "img": ["src", "alt", "title"],
    "code": ["class"],
}

def render_markdown(text: str) -> str:
    html = md.render(text or "")
    clean = bleach.clean(html, tags=ALLOWED_TAGS, attributes=ALLOWED_ATTRS, protocols=["http", "https", "mailto"])
    return bleach.linkify(clean)

For MVP, consider disallowing img or rewriting image src to original GitHub URLs only. Do not serve local attachment files.

Empty DB behavior

If commands that require data run before import:

No ghbb database found at C:\...\ghbb.db.
Run: ghbb import C:\CodeBlocks\ggml-org-backup\backup

If DB exists but has no import:

Database exists but contains no imported backup.
Run: ghbb import [BACKUP_ROOT]