diff --git a/README.md b/README.md index 146ba69..de68a34 100644 --- a/README.md +++ b/README.md @@ -8,30 +8,36 @@ A Claude Code plugin that gives Claude a reference for the `tea` CLI and enforce |---|---| | `/tea:auth` skill | Prompts you to pick a Gitea login and pins it to the project | | `/tea:issue` skill | Issues as units of work — create, read, grep, validate, walk the dependency graph. Entirely offline | -| `/tea:sync` skill | Moves issues between the local store and Gitea — pull, push, comment | +| `/tea:sync` skill | Moves issues between the local store and Gitea — pull, push, comment, close, evict | +| `/tea:page` skill | A discussion's artifacts as a named, ordered tree of pages — import, title, index. Entirely offline | +| `/tea:wiki` skill | Moves page trees between a local space and a Gitea wiki — fetch a subtree, publish one | | `/tea:use` skill | Tea CLI reference for everything that is not an issue — loads command docs on demand | | `tea-runner` agent | Subagent on Haiku that runs the scripts and reports back a receipt — the mechanical half, off your main context | | `tea-guard` hook | PreToolUse hook that blocks or rewrites every `tea` invocation | ## The layering -An issue is a unit of work first and a Gitea row second. Those are two layers, -and knowledge flows one way: +An issue is a unit of work first and a Gitea row second. A page tree is a +discussion's artifacts first and a wiki second. Each is two layers, and +knowledge flows one way: ``` skills/issue DOMAIN what an issue is: format, validation, dependency graph +skills/page DOMAIN what a page tree is: title <-> path, order, the index ▲ offline — no tracker, no network, stdlib only │ imports -skills/sync BRIDGE md <-> Gitea JSON, then over the wire +skills/sync BRIDGE md <-> Gitea issue JSON, then over the wire +skills/wiki BRIDGE md <-> Gitea wiki JSON; transport is sync's _gitea.py ▲ │ calls tea-runner EXECUTION runs the scripts, reports a receipt — no opinions ``` -Delete `skills/sync` and the domain layer keeps working — issues that live only -on your machine are first-class, not drafts waiting to be uploaded. That is the -point of the split: you can plan, write, validate, and track work without a -tracker, and publish only what you choose to. +Delete `skills/sync` and the issue domain keeps working; delete `skills/wiki` +and page trees keep working. Work that lives only on your machine is +first-class, not a draft waiting to be uploaded. That is the point of the +split: you can plan, write, validate, and organize without a tracker, and +publish only what you choose to. ## Prerequisites @@ -120,11 +126,15 @@ session — the pinned login is enforced on every call it makes. agents/ tea-runner.md subagent (Haiku) that executes the scripts hooks/ - hooks.json registers the PreToolUse hook + hooks.json registers the PreToolUse hooks tea-guard.sh the guard (Python 3, no deps) + agents-sync.sh keeps AGENTS.md real and CLAUDE.md a symlink to it skills/ - auth/SKILL.md /tea:auth skill - issue/ /tea:issue — the domain layer, offline + auth/ /tea:auth — the identity layer + SKILL.md + scripts/pin.py where the login pin is and how it is found — + imported by _gitea.py AND by tea-guard.sh + issue/ /tea:issue — the issue domain, offline SKILL.md references/format.md canonical issue format (identity, types, templates) scripts/ Python 3, stdlib only, no network: @@ -135,6 +145,7 @@ skills/ issue_check.py validate against the format issue_ac.py list the body's checkboxes; tick one issue_tree.py draw the dependency graph + issue_evict.py drop closed issues the tracker also has issue_index.py rebuild tmp/issues/INDEX.md sync/ /tea:sync — the bridge to Gitea SKILL.md @@ -145,11 +156,33 @@ skills/ push.py tmp/issues/ -> Gitea, then drops the local file remote.py discovery listing to stdout comment.py post or edit a comment + close.py the state field, both ways + evict.py refresh state: from Gitea, then evict + labels.py put the canonical label set into a repository + page/ /tea:page — the page-tree domain, offline + SKILL.md + references/pages.md canonical page-tree format + scripts/ Python 3, stdlib only, no network: + page.py domain module: title <-> path, ordering, + the manifest, importing, the index + page_import.py copy a directory of markdown into a space + page_index.py write the table-of-contents page + page_ls.py the tree, the titles, one state tag per page + wiki/ /tea:wiki — the bridge to a Gitea wiki + SKILL.md + scripts/ + wikimap.py md <-> Gitea wiki JSON, pure, no I/O + wiki_ls.py what the wiki holds + wiki_pull.py wiki -> tmp/wiki// + wiki_push.py tmp/wiki// -> wiki (additive) use/ /tea:use — tea CLI reference (non-issue entities) SKILL.md references/tea/ command docs ``` +`AGENTS.md` carries the same layout with the reasoning behind it; if the two +ever disagree, `AGENTS.md` is the one being worked from. + ## Local issue store Issues live in `tmp/issues/` (gitignore it) as flat markdown with one metadata diff --git a/skills/sync/SKILL.md b/skills/sync/SKILL.md index 3934539..4045a0b 100644 --- a/skills/sync/SKILL.md +++ b/skills/sync/SKILL.md @@ -355,8 +355,11 @@ A milestone must already exist in the repo — push attaches, it does not create `branch:` is Gitea's `ref`, the branch the work actually lives on. Push fills an empty one with the current git branch (`git rev-parse --abbrev-ref HEAD`) -and writes it back into the issue file; a value already there is never -overwritten, neither on create nor on `--update`. On a detached HEAD or outside +and sends it up as `ref`; a value already there is never +overwritten, neither on create nor on `--update`. Nothing is written back to +the issue file — there is no file left to write to, because a successful push +deletes it. The branch comes back on disk with the next `pull.py `, from +the tracker. On a detached HEAD or outside a git repo no `ref` is sent and a warning names the issues that went up without one. Reading the branch is the only thing these scripts ask git for — they never check out, create, or write anything.