anvilsign in

collin/anvil

BoardRenderedSource

Todo

  • pull mirror (maybe): a repo that virtually mirrors a GitHub repo
    • just displays it here — periodically fetched, read-only on the anvil side
  • pull requests (gix merge)
  • webhooks (mind the SSRF item in docs/untrusted-mode.md)

Edit files in the web UI

Edit a file in the browser and have anvil make a proper commit (author = the logged-in user, sensible message), written straight onto the branch with gix — no working tree. The new commit just advances the branch tip, so anyone who pushed earlier can fast-forward pull it.

  • start minimal: an "Edit" button on the blob page → textarea → commit; commits build the tree/commit objects via gix and move the ref (reject if the branch moved under us — no non-fast-forward clobber). anvil-git/src/edit.rs does the CAS commit; ui.rs edit_form/edit_submit wire the page.
  • a structured way to add items to TODO.md — an "Add task" form that appends a ticket (## title, the richer card style) to the right section per the todo-md round-trip rules (todomd::add_task / task_sections), rather than hand-editing the raw file
  • then richer editing: a real markdown editor with a live render preview (reuse render_markdown) before committing

Image uploads (attachments stored outside git)

Upload an image in the web editor and link to it from the markdown without the blob ever entering git history. Stored content-addressed per repo and served back; the file only carries the URL.

  • store: content-addressed blobs at data/attachments/{repo_id}/{sha256}, deduped per repo; Attachment model maps repo_id/hash → content-type, size, uploader, created-at. Kept out of repositories/ so it's never a git object. (anvil-core: attachments, storage::attachment_path, schema shim.)
  • serve: GET /{owner}/{repo}/-/attachments/{hash}, read-access gated (private repos stay private), immutable cache + nosniff + locked-down CSP.
  • upload: POST /{owner}/{repo}/-/attachments behind write-access + CSRF (X-CSRF-Token header), magic-byte sniffed to png/jpeg/gif/webp (SVG rejected), capped by http.attachment_max_mb, returns the markdown to splice.
  • editor UX: paste or drop an image in the file editor → background upload → ![image](url) inserted at the cursor.
  • caps: per-repo attachment quota (http.attachment_quota_mb, 0 = unlimited) — a new upload over the cap is rejected; deduped re-uploads are always free. (Reject, not evict: evicting would break live Markdown links.)
  • within-repo reclaim: an orphan sweep (delete attachments no committed file references) and/or a per-attachment delete action — the recourse once a repo hits its quota. Deferred: deletion is destructive and "orphaned" is fuzzy (tip-only vs any-ref), so it wants its own design pass.
  • remove a repo's attachment + artifact dirs on repo delete — blocked: there is no repo-delete path yet (only the create-rollback uses it).

Admin: site disk-usage dashboard

  • /-/admin/usage (admin-only; 404 for everyone else, nav link for admins): actual on-disk bytes per user, broken down by content type (repositories / CI artifacts / attachments) with column + grand totals. anvil-core::usage walks the stores; storage::dir_size sums them.
  • maybe: per-repo drill-down, and a cheap cached/periodic variant if the on-demand disk walk gets slow on large instances.

API tokens (read-only PATs)

  • ApiToken model + anvil-core::api_tokens (create/list/revoke, SHA-256 hashed, scoped). CLI anvild user token create|list|revoke.
  • bearer auth: CurrentUser also accepts Authorization: Bearer <pat> on GET/HEAD only — least-privilege read-only (writes need a session CSRF a bearer lacks). Lets tooling (and Claude) fetch private-repo attachments over HTTP. See the recipe in CLAUDE.md.
  • token management on the user settings page (/-/settings): create (secret shown once), list, and revoke — ownership-enforced.
  • maybe later: a write scope (would need CSRF-exempt write paths) and last_used_at tracking.

UI polish (done)

  • less vertical padding at the top of the screen (main top padding 24→12px)
  • kanban card details: the disclosure toggle restyled to a clean uppercase marker, and the expanded detail text is no longer de-emphasized (full --fg, not muted)
  • kanban card images constrained to the card width (max-width:100%); they were rendering at natural size on the board while fine on the rendered page

implement delete task

Implement delete task functionality from the todo.md editor.