# Snippets: implementation plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** A snippet a user owns, shares by URL, and edits in place: one or more named text files, a description, and a visibility. Closes #195. **Architecture:** Two new tables (migration 0054) hold snippets and their files; content sits in SQLite as a BLOB. Eight `snippet` control commands in `internal/control/snippet.go` are the only write path; the CLI, the JSON API and the web forms dispatch into them. Read rules live in `internal/policy/snippets.go`. The web renders under `/{owner}/-/snippets`, the pattern `/{owner}/-/labels` set. **Tech Stack:** Go, SQLite via modernc (hand-written SQL, no ORM), Go `html/template`, chroma through the existing `highlight`, the control registry in `internal/control`, the e2e harness in `e2e/`. **Spec:** `docs/specs/2026-09-11-snippets-design.md` ## Global Constraints - Every capability lands as a control command first; the CLI, web and API dispatch into it. New commands need a `pass()` row in `cmd/gitbay/main.go` (`TestCLI` in `e2e/cli_test.go` enforces this) and, if `ReadOnly`, a row in `readArgs` in `e2e/readonly_test.go` (`TestReadOnlyCommandsWriteNothing` enforces that). - A command that reads stdin sets `ReadsStdin: true`, or `control.go` swaps in an empty reader and `--file -` stores nothing without an error. - Hand-written SQL only. Migrations are `internal/store/migrations/NNNN_name.up.sql` and `.down.sql`, embedded, run one per transaction; `TestMigrateUpDown` runs both directions. - Private things return not-found (exit 3, HTTP 404), never a denial that confirms they exist. - Every `` and `

{{end}} ``` In `internal/web/templates/snippet.html`, inside the `{{range .Files}}` section after `
{{.HTML}}
`, add: ```html {{if $.CanWrite}}
edit {{.Name}}

{{end}} ``` and after the `{{end}}` that closes the range, before the final `{{end}}`: ```html {{if .CanWrite}}
add a file

settings

{{end}} ``` If `.editbox` or `.commentform` render poorly beside `.code`, add a `.snippetfile { margin-bottom: 1.5rem }` rule to `internal/web/static/style.css`; nothing more. - [ ] **Step 6: Build and run the tests** Run: `go build ./... && go vet ./... && go test ./internal/httpd && go test ./e2e -run 'TestSnippetsWeb$'` Expected: PASS. `internal/httpd` carries the structural checks: `TestMutatingRoutesRequireCheckOrigin` (every `Mutating` route is wrapped in `checkOrigin`), `TestViewOnlyHasNoMutatingRoutes` (the POST routes sit inside the accounts block), and the input-label test on `snippetnew.html` and the new forms. - [ ] **Step 7: Commit** ```bash git add internal/httpd/snippets.go internal/httpd/routes.go internal/web/templates/snippet.html internal/web/templates/snippetnew.html e2e/snippetweb_test.go git commit -m "web: create, edit and delete snippets Every form dispatches the snippet command the CLI runs. Ref #195" ``` --- ### Task 5: Documentation and changelog **Files:** - Modify: `.gitbay/wiki/Users.org` (a `* Snippets` section after `* Pages`, before `* Browser sessions`) - Modify: `.gitbay/wiki/Parity.org` (rows after `release asset remove`) - Modify: `.gitbay/wiki/Admin.org:116` (the `[limits]` list) - Modify: `CHANGELOG.org` (a new top entry) - [ ] **Step 1: Users.org** Insert before `* Browser sessions`: ```org * Snippets A snippet is one or more named text files you own outside any repository, for a log or a fragment shared by URL. Create one from a file on stdin; the reply is the id and the URL: #+begin_src sh gitbay snippet create build.log --description "failing build" < build.log gitbay snippet file set notes.txt < notes.txt # add or replace a file gitbay snippet file get build.log > build.log gitbay snippet edit --visibility public gitbay snippet list # yours gitbay snippet list # their public ones gitbay snippet delete #+end_src Visibility is =public= (listed on your page), =unlisted= (anyone with the URL, listed nowhere; the default) or =private= (you alone; not found to everyone else). Files are text, valid UTF-8, each under the instance's =max_snippet_bytes=, at most 64 per snippet. A snippet keeps at least one file. There is no history: setting a file replaces it. On the web, =//-/snippets= lists yours, each snippet page renders its files with a raw link per file, and the same page creates, edits and deletes through the commands above. ``` - [ ] **Step 2: Parity.org** After the `release asset remove` row add: ```org | snippet create, edit, delete | yes | yes | no | | snippet show, list | yes | yes | no | | snippet file set, get, remove | yes | yes | no | ``` Match the table's column alignment by hand; org tables tolerate ragged cells but the page is read raw too. - [ ] **Step 3: Admin.org** After the `max_asset_bytes` line in `** [limits]` add: ```org - =max_snippet_bytes= (1MB) — cap per snippet file. ``` - [ ] **Step 4: CHANGELOG.org** Before `* v1.19.0 — 2026-09-11` add: ```org * v1.20.0 — unreleased Snippets (#195): named text files a user owns outside any repository, shared by URL and edited in place. - Migration 0054: =snippets= and =snippet_files=. - =snippet create|show|list|edit|delete= and =snippet file set|get|remove=. Files are UTF-8 under =limits.max_snippet_bytes= (1MB), at most 64 per snippet; a snippet keeps at least one. Visibility =public=, =unlisted= (default) or =private=; a private snippet is not found to everyone but its owner and admins. - Web: =//-/snippets= lists, each snippet page renders its files with a raw route per file, and the owner creates, edits and deletes from the page through the same commands. The owner page links to the list. ``` - [ ] **Step 5: Commit** ```bash git add .gitbay/wiki/Users.org .gitbay/wiki/Parity.org .gitbay/wiki/Admin.org CHANGELOG.org git commit -m "wiki, CHANGELOG: snippets Closes #195" ``` --- ### Task 6: Merge request - [ ] **Step 1: Push and open the MR** ```bash git push -u origin snippets gitbay mr create --source snippets --target main --title "Snippets (#195)" --file - <<'EOF' Named text files a user owns outside any repository, shared by URL and edited in place. Spec: docs/specs/2026-09-11-snippets-design.md. Migration 0054. Commands snippet create|show|list|edit|delete and snippet file set|get|remove; web under /{owner}/-/snippets with forms dispatching the same commands. New limit max_snippet_bytes (1MB). Closes #195 EOF ``` - [ ] **Step 2: Wait for CI, then merge** Check `gitbay build list --json` until the build for the branch head succeeds; read `gitbay build log ` on failure and fix on the branch. Then: ```bash gitbay mr merge --strategy ff git push origin --delete snippets ``` and remove the worktree and branch locally after the merge lands.