WikiTicket SDD
Wiki ticket — pronounced "wicked ticket". WikiTicket Spec-Driven Development.
Why
Teams want spec-driven development that works across multiple teams and is visible to everyone — fishbowl AI-assisted development. You can use AI heavily, but the work is never hidden: every plan becomes tracked tickets, the history of what was done is readily available, and roadmaps and status reports are generated artifacts anyone can read. No "the agent did a bunch of stuff last week and nobody knows what."
Two things set this apart from other git-native agent trackers:
- Plans are frozen. Written once, never regenerated. A changed design gets a new dated plan that supersedes the old one. The record of why an approach was abandoned is the most valuable artifact.
- Documents carry the commit they were written against.
git_hashin front matter names the tree the author had open;worklog doc-verifyresolves everypath — symbol(), lines N–Mcitation at that commit, telling a fabricated citation (wrong even then) apart from drift (right then, the code moved). It never falls back to HEAD.
The JSONL event log is the mechanism, not the headline. An essay mapping
the machinery onto the mid-2026 "graph engineering" framing lives at
docs/graph-engineering.md.
Compared with beads, spec-kit, and GitHub Projects
The append-only JSONL-in-git log overlaps beads and backlog.md-style agent trackers. That's table stakes. The difference is what sits on top of the log.
| Frozen plans | Citation provenance | Tracker / wiki | |
|---|---|---|---|
| WikiTicket SDD | Written once, superseded not edited | git_hash + doc-verify at that commit | Bidirectional, to the team's existing systems |
| beads | No | No | Local-first log; not a wiki/tracker publisher |
| spec-kit / OpenSpec | Living specs, updated in place | No | Spec artifacts, not tickets |
| GitHub Projects | No | No | The board is GitHub |
spec-kit and OpenSpec generate living spec.md / plan.md / tasks.md.
WikiTicket can ingest their task lists via plan-capture, then freeze the
why as a dated plan. GitHub Projects is a board on issues; WikiTicket is
local-first and optionally publishes to GitHub (or Jira, ADO, …).
A plan is the why of a piece of work; an ADR is the why of a standing decision. Neither is a living spec.
What it does
- Plans are the permanent design record. Exiting plan mode captures the
plan to
docs/plans/and emits tracked items. Planning never evaporates; when you need the why, read the plan. Plans are written once and superseded, never edited. - Documents carry the commit they were written against, and a gate reads
it back.
git_hashin front matter says which tree the author had open;worklog doc-verifyresolves everypath — symbol(), lines N–Mcitation at that commit, telling a fabricated citation (wrong even then — a defect) apart from drift (right then, the code moved since). It never falls back to HEAD.worklog provenance-backfilladdsmerged_inonce the document lands. At release,doc-verify --strictalso reportsSTALEwhen a live design doc'sgit_hashpredates the latest tag or the tag has no freeze record indocs/designs/, so a release cannot ship with the live pair left unregenerated. - Append-only, git-native work log. Epics, stories, tasks, subtasks, and
bugs live in
.work/todo.jsonl— an event log that multiple people (and agents) can work against concurrently. Union merge, event fold: branches merge cleanly, state is derived by folding events. Nightly compaction snapshots closed items intodone.jsonland ages them intoarchive.jsonlper level; nothing is deleted, andshowandlist --allfold all three files. - A four-axis work taxonomy. Every item sits on
level(epic/story/task/subtask),kind(feature/bug/ops/triage),milestone(what ships together), and planned-vs-discovered. The unclassified default istriage— visible in the roadmap's needs-classification queue, never a silent guess. - A small fixed core, plus optional fields your team switches on.
estimate,owner,risk, andacceptance_criteriaship enabled;value,confidence,due_date, andseverityare available and off. A disabled field is invisible, not rejected — no flag is built for it, so it never appears in--helpor in anything an agent reads.worklog fieldsprints the catalog and what each field means;work_item_fieldsin.work/config.ymlis the switch. - Generated roadmap and status reports.
docs/roadmap.mdis rendered from the log — no hand-editing, no drift. - Design docs and code walkthroughs, generated from the actual code at
every release: a live
current_*pair plus a short freeze note (tag + git_hash + delta from the previous freeze). Existing full dated copies stay frozen. Prose usesdocument-specialistv3.2.2 (STE100 default). Diagrams default todesign-doc-mermaidv1.1.1.plantumlv1.2.2 is leftover types only and always PNG/SVG. Install the suite fromSpillwaveSolutions/spillwave-documentation-marketplacev0.2.1. - Information architecture & content model. Stable
wiki_keyidentity,truth_state(current vs snapshot/superseded), a generated reader plane (Home, Sidebar, Decisions/Releases/Status/Traceability indexes), and a typed-edge graph (worklog ia-index,ia-graph,trace-check,ticket-body,link-pr). Wiki publish followsdocs/.index/publish-manifest.json, which also carries a generated page per ticket, PR, and release (worklog ia-ticket <ULID>to preview one). - Syncs to the team's OWN systems — wiki and tickets. Your work log
publishes to whatever your team already uses. Create-vs-update consults
the remote: a clone with no link memory finds the item's ticket by its
marker and updates it instead of filing a second one, and
worklog sync --explain <ULID>says which source answered. - Living integration guides, one per SDD tool and ticket/wiki system
(Superpowers, GSD, SpecKit, OpenSpec, Jira, Confluence, GitHub, GitLab,
Azure DevOps, AWS CodeCatalyst, Google Cloud DevOps), fetched from the
wiki at runtime with a local fallback under
docs/integrations/— see theintegration-guideskill.
System-agnostic edges, deliberately
Works equally with GitHub, GitLab, Azure DevOps (wiki + work items), Jira,
Linear, AWS CodeCatalyst, Confluence — and other is a first-class config
value for anything else. The team picks. (GCP ships no native tracker;
GCP-hosted teams pick from the list like everyone else.)
The core never contains per-system code. Publishing and sync are done by
skills that instruct the AI to use whatever CLI, MCP server, or skill is
available for the chosen system, researching missing tooling at runtime. The
integration-guide skill points at a living, wiki-hosted setup guide per
system (Jira, Confluence, GitHub, GitLab, Azure DevOps, AWS CodeCatalyst,
Google Cloud DevOps — plus Superpowers, GSD, SpecKit, and OpenSpec on the SDD
side), with a local fallback copy under docs/integrations/ when the wiki
page is unreachable — knowledge that lives in docs, not hard-coded into the
skill set. You could even run two trackers at once (GitHub + Jira) — the
workflow stays identical.
Quick start (no plugin)
Clone, then wire the git hooks:
git config core.hooksPath hooks
Track work with the CLI:
bin/worklog add "Extract auth middleware" --level task --kind feature \
--milestone v0.7.0 --priority P0
bin/worklog add "Fix flaky retry" --kind bug --unplanned --discovered-during <id>
bin/worklog update <id> --status in_progress
bin/worklog close <id>
bin/worklog list
bin/worklog fields # which item fields this repo has switched on
bin/worklog find <text> # search the generated inventory and graph
Capture a plan and regenerate the roadmap:
bin/worklog plan-capture --slug my-plan --title "My plan" --file draft.md
bin/worklog roadmap-render
The pre-commit and pre-merge-commit hooks enforce the invariants: trailing
newline on the log, event schema validation, no unresolved conflict markers in
any staged file (no merge exemption — a merge is exactly when a missed
hunk slips through), and roadmap.md freshness — plus branch discipline:
pre-commit rejects a commit authored directly on main/master (merges via
git merge origin/main are exempt), and commit-msg requires every commit
message to reference a worklog item (26-char ULID) or a ticket (#123), merge
commits exempt.
Nightly compaction runs in CI on main. When one lands mid-session and blocks
your merge — union merge resurrects events a compaction already folded, and
would silently drop the ones your branch wrote below the watermark —
bin/worklog merge-rescue, run from inside the blocked merge, keeps the
compacted log and replays your branch's own events above the watermark.
Recompacting is not the fix: it would verify green while making the loss
permanent.
House rules, enforced
Policy that holds because tooling holds it, not because people remember:
- PRs merge only when every gate is green.
/worklog:mergearmsgh pr merge --auto --mergeso GitHub merges when required checks pass (ADR-0011, which supersedes ADR-0010: bot PRs land through the same gate under a PAT identity, never a bypass actor); the poll loop is fallback. Never--admin, never squash (ADR-0008), never bypass. Teams that want a human on the trigger setfeatures.auto_merge_on_green: falsein.work/config.yml(advisory mode: report green, human merges). - Coverage floor. CI enforces >=80% line coverage on
bin/*.py; the target is 95%. - Frozen artifacts. Plans, roadmap snapshots, and published status reports are written once and never regenerated — corrections go in new documents. Frozen means the prose: metadata stamps in front matter are still allowed, and since the publish manifest hashes the body, they no longer look like edits.
- The roadmap is generated. Never hand-edited; to change it, change the work items and re-render.
- One session per working directory.
worklogwarns when two assistant sessions share a checkout — one switches branches under the other mid-operation and both "fix" the same thing differently. The warning is advisory and arrives after the fact; the fix is agit worktreeper session. - Provenance on every event, and on every generated document. Each event
carries the short HEAD sha it was written at
(
WORKLOG_NO_GIT_PROVENANCEopts out). Ids keep their full entropy — provenance is a field, never spent out of the identifier. Plans, status reports, ADRs and the roadmap carry agit_hashnaming the tree they were written against, which is what makesworklog doc-verifypossible. It depends on this repo using merge commits (ADR-0008); under squash-merge the verifier reportsunresolvableand refuses rather than checking against the wrong tree.
Multi-host
| Host | How it loads |
|---|---|
| Claude Code | Marketplace worklog@worklog-marketplace (plugin/.claude-plugin) |
| Grok Build | Claude-compatible, zero-config |
| Codex | plugin/.codex-plugin + plugin/hooks/codex-hooks.json |
| Agent Plugins 1.0 | Root plugin.json and plugin/plugin.json |
| Grok Bot | Skills + docs/GROK_BOT.md |
| LangChain Deep Agents | plugin/skills/ — docs/LANG_CHAIN_DEEP_AGENTS.md |
Two merge models: worklog is append-only ULID events; knowledge-tree writes use worktree + PR. See docs/ISOLATION.md. Public examples use fictional lumenfield-detector and northstar-console only.
Also: Onboarding.
Claude Code, Codex, and Grok Build plugins
The plugin (in plugin/) packages the skills, /worklog:*
commands (including /worklog:merge, the green-gates merge loop), and the
ExitPlanMode capture hook. Install from this repo's marketplace:
claude plugin marketplace add <this-repo-url-or-path>
claude plugin install worklog@worklog-marketplace
Codex uses the same marketplace and the native manifest at
plugin/.codex-plugin/plugin.json:
codex plugin marketplace add SpillwaveSolutions/wiki_ticket_sdd
codex
# Open /plugins, install worklog, then start a new session.
Codex discovers the bundled skills natively, and gets the enforcement hooks
too — the prompt reminder, the stop check, and the session doctor all run
there. The scripts are shared, not ported: Codex sets CLAUDE_PLUGIN_ROOT
for plugin-sourced hooks and reads the same additionalContext output, so
only the wrapper differs (plugin/hooks/codex-hooks.json nests the event map
under a hooks key).
Plan capture is the exception. That hook fires on PostToolUse matching the
ExitPlanMode tool, and Codex has the event but no such tool — so on Codex
plan capture is what AGENTS.md says it is, and you run
bin/worklog plan-capture ... before implementing. Claude Code and Grok Build
are unchanged.
Two install levels, deliberately distinct:
- Plugin install (above) — every session gets the skills, commands, and
hooks. Global; changes no repo. Upgrade if you installed before 0.22.1:
the hook manifest declared its events at the top level and the loader reads
them from under a
hookskey, so every hook silently did nothing for everyone who installed the plugin. Nothing failed, nothing warned. After upgrading, hooks start firing that never did — the prompt reminder, session doctor, stop check and plan-capture prompt are not new, they are what you already installed, working for the first time. - Repo install — inside a target repo, run
/worklog:init. It scaffoldsbin/, the git hooks, an empty.work/withconfig.yml, and the CI check (.github/workflows/worklog.yml, orazure-pipelines.ymlwhen the origin remote is Azure DevOps). The copies are committed, so hooks and CI work for teammates who don't have the plugin.
Also: /worklog:uninstall removes the tooling but never touches .work/
data, docs/plans/, docs/status/, or docs/roadmap.md — the data
outlives the tooling. /worklog:doctor reports version drift and invariant
violations without changing anything. Ticket sync runs through a typed
adapter contract: worklog adapter check validates an adapter against the
contract before anything activates.
Other harnesses (OpenCode and Grok Build)
The repo scaffold is harness-independent: bin/worklog, the git hooks, and
CI are committed and work from any shell. The AGENTS.md symlink (created
by /worklog:init, pointing at CLAUDE.md) carries the full worklog policy
to any harness that reads AGENTS.md — but init only creates those two
files, it does not commit them. Run git ls-files CLAUDE.md AGENTS.md; empty
output means a fresh clone gets no policy, and git ls-files -s AGENTS.md
should read mode 120000 so the symlink was stored as a symlink, not a copy.
Grok Build is fully compatible with
Claude Code with zero configuration — per the xAI docs it automatically reads
Claude Code marketplaces, plugins, skills, MCPs, agents, hooks, and
instruction files. See
plugin/PORTS.md for the support matrix and porting guide.
How it works
The full design — event schema, fold semantics, merge behavior, sync model — is in docs/worklog-spec.md. Task-oriented guides (concepts, CLI reference, plugin guide) live in docs/user_guide/.
Layout
| Path | What |
|---|---|
.work/ | Append-only event log (todo.jsonl, done.jsonl, archive.jsonl), config.yml, publish ledger |
adapters/ | Ticket-sync adapters: shipped fake (CI double) and github (worked example), plus authoring rules |
schema/ | JSON Schemas: adapter contract, ADR, document IA (doc.schema.json), entity/item |
bin/ | worklog CLI plus its Python modules (fold, sync, roadmap, plan capture, IA, …) |
docs/plans/ | Captured plan documents (frontmatter links plans to items) |
docs/status/ | Generated status reports |
docs/roadmap.md | Generated roadmap — do not edit |
docs/adr/ | Architecture Decision Records |
docs/designs/ | Current + frozen design docs and code walkthroughs |
docs/.index/ | IA inventory, graph, publish manifest, sidecars, rendered Home/Sidebar/indexes |
docs/user_guide/ | User guide, CLI reference, plugin guide |
docs/integrations/ | Living per-system setup guides (11 SDD tools + ticket/wiki systems), published to the wiki and used as the integration-guide skill's offline fallback |
hooks/ | pre-commit, pre-merge-commit, commit-msg, exit-plan-capture.sh, prompt-reminder.sh, session-doctor.sh, session-end.sh, stop-worklog-check.sh |
plugin/ | Claude Code, Codex, and Grok Build manifests, commands, skills, hooks, and canonical scripts — v0.24.12 |
tests/ | Unit and integration tests |
Testing
for t in tests/test_*.py; do python3 "$t"; done
Stdlib unittest only — no pytest, no dependencies. Unit suites cover the
fold, ULIDs, roadmap rendering, and plan capture; tests/test_integration.py
simulates full PR flows (branch, track, merge, fold) in throwaway git repos.