ticketwright 4.0.0__tar.gz → 4.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/config/stack.schema.md +1 -1
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/settings.json.tmpl +1 -1
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/setup/SKILL.md +42 -3
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/setup/interview.md +6 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/setup/scaffold.md +3 -2
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/setup/teammate.md +25 -2
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/ticket/SKILL.md +29 -17
- {ticketwright-4.0.0 → ticketwright-4.0.2}/CHANGELOG.md +73 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/PKG-INFO +119 -13
- {ticketwright-4.0.0 → ticketwright-4.0.2}/README.md +118 -12
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/effective_config.py +57 -0
- ticketwright-4.0.2/bin/plugin_doctor.py +669 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/selftest.sh +936 -9
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/update_notice.py +147 -21
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/verify_stack.sh +13 -1
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/AGENTS.md.tmpl +86 -6
- {ticketwright-4.0.0 → ticketwright-4.0.2}/ticketwright/__init__.py +1 -1
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/agents/qc-reviewer.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/commands/.gitkeep +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/config/connections.example.yaml +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/config/stack.example.asana-bq.yaml +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/config/stack.example.azure.yaml +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/config/stack.example.multi-audience.yaml +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/config/stack.example.multi-warehouse.yaml +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/config/stack.example.no-warehouse.yaml +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/config/stack.example.solo.yaml +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/config/stack.yaml +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/config/viewer.example.yaml +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/hooks/_stack.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/hooks/db_write_guard.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/hooks/regenerate_ticket_index.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/hooks/session_context.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/hooks/source_material_guard.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/hooks/ticket_index_context.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/refresh/SKILL.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/refresh/context-pack.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/refresh/index.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/review/SKILL.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/setup/adopt.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/setup/voice.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/ship/SKILL.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/skillify/SKILL.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/skillify/authoring.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/spec-and-build/SKILL.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/skills/ticket/priming.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.claude/statusline.sh +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/.gitignore +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/LICENSE +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/README.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/chat/gmail.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/chat/outlook.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/chat/slack.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/chat/teams.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/docstore/gdrive.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/docstore/rclone.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/docstore/sharepoint.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/meetings/fireflies.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/meetings/granola.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/meetings/notion.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/meetings/teams.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/meetings/zoom.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/runtime/antigravity.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/runtime/claude-code.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/runtime/cline.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/runtime/codex-cli.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/runtime/cursor.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/runtime/devin.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/runtime/opencode.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/tracker/asana.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/tracker/azure-devops.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/tracker/github-issues.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/tracker/jira.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/tracker/linear.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/tracker/local.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/tracker/monday.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/vcs/azure-repos.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/vcs/github.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/vcs/gitlab.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/viewer/macos-open.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/viewer/windows-start.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/viewer/xdg-open.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/warehouse/bigquery.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/warehouse/databricks.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/warehouse/postgres.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/warehouse/redshift.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/warehouse/snowflake.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/adapters/warehouse/synapse.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/_yamlite.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/build_ticket_index.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/bump_version.sh +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/delivery_plan.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/emit_runtime.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/enrich_ticket.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/handoff.sh +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/hook_shim.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/ingest_index_records.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/install.sh +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/kit_paths.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/meeting_refs.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/opencode_tool_gate.js +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/recall.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/render.sh +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/render_and_validate.sh +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/resolve_user.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/scan_source_materials.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/split_and_export.sh +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/sql_scan.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/tw +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/bin/whoami.py +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/pyproject.toml +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/CLAUDE.md.tmpl +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/generated-skill/SKILL.md.tmpl +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/generated-skill/bin/drift_check.sh +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/generated-skill/golden/example.json +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/generated-skill/sql/qc.sql.tmpl +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/generated-skill/sql/step.sql.tmpl +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/generated-skill/templates/README.md.tmpl +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/generated-skill/templates/tracker_comment.txt.tmpl +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/gitignore.tmpl +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/person.yaml.tmpl +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/plan.md.tmpl +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/project-README.md.tmpl +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/roles/analyst.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/roles/engineer.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/roles/generalist.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/roles/scientist.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/spec.md.tmpl +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/ticket-README.md.tmpl +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/templates/voice-profile.md.tmpl +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/tests/emit/README.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/tests/meeting_refs/README.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/tests/source_materials/README.md +0 -0
- {ticketwright-4.0.0 → ticketwright-4.0.2}/ticketwright/cli.py +0 -0
|
@@ -114,7 +114,7 @@ policies: # behavioral rules every skill inherits (the kit's "global rules
|
|
|
114
114
|
| `key_prefix` | string | `ENG` | Ticket-ID prefix. Branch names = `{key_prefix}-NNNN`. Omit it when `id_mode: slug` — there are no keys to prefix. |
|
|
115
115
|
| `id_mode` | enum | `keyed` | `keyed` (default) = folder names carry a tracker key; `slug` = the folder name **is** the id. See "Trackerless work". |
|
|
116
116
|
| `key_prefixes` | list | `[ENG]` | Prefixes the ticket index recognizes in folder names. Optional; defaults to `[key_prefix]`. Use when one repo holds tickets from several trackers (e.g. `[ENG, OPS]`). |
|
|
117
|
-
| `assignee_dir` | string | `alice` | Last-resort owner subdir under `tickets/`, used only when no people map exists (`bin/whoami.py` returns `miss` and there are no `people/*.yaml`). With a people map, the whoami-resolved person is the owner. |
|
|
117
|
+
| `assignee_dir` | string | `alice` | Last-resort owner subdir under `tickets/`, used only when **no people map exists at all** (`bin/whoami.py` returns `miss` and there are no `people/*.yaml`). With a people map, the whoami-resolved person is the owner, and an unresolved person is a **hard stop** — never this key, which would file a new teammate's work in a colleague's folder. `effective_config.py` reports which case applies as `owner_source` (`resolved` / `unbound` / `assignee_dir_fallback` / `none`) and the answer as `owner`. |
|
|
118
118
|
| `ticket_path` | template | `tickets/{assignee}/{id}` | Where a ticket folder lives. `{assignee}` `{id}` tokens; `{assignee}` is the ticket's **owner** — the whoami-resolved person for new work, or the locator's owner (`owner/id`) when named explicitly. |
|
|
119
119
|
| `ticket_subdirs` | list | `[source_materials, final_deliverables, qc_queries, exploratory_analysis]` | Scaffolded per ticket. |
|
|
120
120
|
| `default_epic` | string \| null | `ENG-100` | Parent epic for newly created tickets (null if tracker has no epics). |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_README": "Rendered to .claude/settings.json by /setup. The hooks block below is for a VENDORED (cp -r) install, where nothing else wires the kit's hooks. On a PLUGIN install (CLAUDE_PLUGIN_ROOT set), .claude-plugin/plugin.json already wires these same hooks from the plugin dir, so /setup OMITS this hooks block to avoid double-firing (double db-write prompts, double index regen) AND MERGES an 'extraKnownMarketplaces' (ticketwright source {source:'git', url:'https://github.com/kyle-chalmers/ticketwright.git'} — the discriminator `claude plugin marketplace add` writes itself; 'git' and 'url' are different source types — plus autoUpdate:true) + 'enabledPlugins' (ticketwright@ticketwright:true) block so the REPO opts every user into the plugin at PROJECT scope (a plugin cannot set its own install scope — the repo does; teammates
|
|
2
|
+
"_README": "Rendered to .claude/settings.json by /setup. The hooks block below is for a VENDORED (cp -r) install, where nothing else wires the kit's hooks. On a PLUGIN install (CLAUDE_PLUGIN_ROOT set), .claude-plugin/plugin.json already wires these same hooks from the plugin dir, so /setup OMITS this hooks block to avoid double-firing (double db-write prompts, double index regen) AND MERGES an 'extraKnownMarketplaces' (ticketwright source {source:'git', url:'https://github.com/kyle-chalmers/ticketwright.git'} — the discriminator `claude plugin marketplace add` writes itself; 'git' and 'url' are different source types — plus autoUpdate:true) + 'enabledPlugins' (ticketwright@ticketwright:true) block so the REPO opts every user into the plugin at PROJECT scope (a plugin cannot set its own install scope — the repo does; registering the marketplace is not installing the plugin, so teammates must still run the two --scope project install commands themselves, README Track 2), committed with the repo, and self-updates on formal releases only (version-string change; never un-released main commits). The documented install already writes most of that block via `--scope project` on both `marketplace add` and `plugin install` (everything except autoUpdate), so setup MERGES into those two maps — preserving unrelated entries, an existing ticketwright source (a fork edits that URL), and any explicit autoUpdate:false — rather than overwriting. Do NOT add those two keys on a vendored install — there is no marketplace to enable from. permissions + statusLine are written in both modes (setup appends stack-specific CLI allows); on a plugin install setup copies statusline.sh into .claude/ so the relative command resolves. The db_write_guard hook turns 'db_write_requires_approval' into a mechanical ask before any destructive warehouse statement; the source_material_guard hook turns 'source_material_guard' into a mechanical ask before a raw meeting transcript is staged for commit or copied into a docstore backup.",
|
|
3
3
|
"hooks": {
|
|
4
4
|
"PreToolUse": [
|
|
5
5
|
{
|
|
@@ -130,6 +130,34 @@ which prints the resolved commands without launching anything. Never commit this
|
|
|
130
130
|
## Default mode — configure the repo
|
|
131
131
|
|
|
132
132
|
### Phase 1 — Detect (no questions yet)
|
|
133
|
+
0. **Preflight — the ways a run is doomed before it starts.** Both probes are read-only and cheap;
|
|
134
|
+
run them before anything else, because neither failure is fixable by anything this skill writes.
|
|
135
|
+
- **Is this a clone?** `!git rev-parse --show-toplevel` — a non-zero exit means there is no
|
|
136
|
+
repository here. **Halt**, and say why: "There is no `.git` in this folder. If it came from a
|
|
137
|
+
Download-ZIP button (the folder name usually ends in `-main`), Ticketwright cannot branch,
|
|
138
|
+
commit, or open a PR from it, and no config would fix that. Clone the repo instead —
|
|
139
|
+
`git clone <the repository's URL>` — then re-run `/setup` inside the clone."
|
|
140
|
+
- **Is the kit installed and usable here?**
|
|
141
|
+
`!python3 "${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/bin/plugin_doctor.py" --json` — one
|
|
142
|
+
read-only pass over the install prerequisites (it never installs anything, and makes no
|
|
143
|
+
network call). Report **every** finding that is not `ok`, each with its `fix` lines
|
|
144
|
+
**verbatim**: they are exact commands, and a paraphrased command is one nobody can run.
|
|
145
|
+
A `fail` on any of these three is a **halt**, because nothing setup writes reaches the cause:
|
|
146
|
+
- `scope_supported` — the agent CLI is too old to install a plugin for one repo; the fix names
|
|
147
|
+
both the in-session install route and the update command for how it was installed;
|
|
148
|
+
- `repo_install` — nothing is installed for this repository;
|
|
149
|
+
- `install_payload` — the install record points at a directory that does not exist.
|
|
150
|
+
Everything else (`warn`, `unknown`, a global-only install, a stale catalog) is reported and
|
|
151
|
+
the run continues. On a non-plugin install — a vendored kit, a pip install — the install
|
|
152
|
+
checks answer `unknown`: that is the expected answer there, not a failure. If the script is
|
|
153
|
+
absent (an older kit copy), say so in one line and carry on.
|
|
154
|
+
- **`yq`** — when `yq_present` is not `ok`, Phase 4's kit-integrity check cannot run at all.
|
|
155
|
+
Print the platform install command the doctor gives, and **offer to run it now**, while it is
|
|
156
|
+
still cheap — not at the moment the check fails. Say in the same breath what that check costs:
|
|
157
|
+
it runs 1,200+ assertions over several minutes, longer than a typical tool timeout, so give it
|
|
158
|
+
the background or a raised timeout and judge it by its **exit code**, never by whether the
|
|
159
|
+
tail of its output looks green.
|
|
160
|
+
Identity routing is unchanged: it happens at step 4 below.
|
|
133
161
|
1. **CLIs:** `!for c in snow acli gh glab bq databricks yq jq git rclone; do command -v $c >/dev/null && echo "✓ $c" || echo "– $c"; done`
|
|
134
162
|
2. **MCP servers** connected this session (tracker / chat / warehouse servers).
|
|
135
163
|
3. **Repo facts — probes, not questions.**
|
|
@@ -140,7 +168,9 @@ which prints the resolved commands without launching anything. Never commit this
|
|
|
140
168
|
confirms instead of asking. The default branch comes from
|
|
141
169
|
`git symbolic-ref refs/remotes/origin/HEAD` — **not** `git symbolic-ref HEAD`, which reports
|
|
142
170
|
whatever branch happens to be checked out and would misconfigure any setup run from a
|
|
143
|
-
feature branch.
|
|
171
|
+
feature branch. On a repo nothing has been pushed to yet that probe exits 128 ("not a
|
|
172
|
+
symbolic ref") — fall back to the current local branch and confirm it in prose; never leave the
|
|
173
|
+
agent to improvise on a failed probe.
|
|
144
174
|
- **Obsidian:** installed or not (e.g. `command -v obsidian`, or the OS application folder).
|
|
145
175
|
Never a question — `graph_notes`/`graph_config` already default correctly; this only decides
|
|
146
176
|
which one-liner the Phase-4 report prints (step 8).
|
|
@@ -258,7 +288,9 @@ Only on explicit confirmation, execute — **source of truth first, derived file
|
|
|
258
288
|
7. **Two distinct checks — keep them labeled as such in the report:**
|
|
259
289
|
- `!bash "${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/bin/selftest.sh"` — **kit integrity**. It
|
|
260
290
|
validates the plugin's *own bundled example* stacks, **not** your repo's config. A failure here
|
|
261
|
-
is fatal.
|
|
291
|
+
is fatal. It runs 1,200+ assertions and takes several minutes — longer than a typical
|
|
292
|
+
tool timeout, so run it in the background or with a raised timeout, and judge it by its exit
|
|
293
|
+
code (non-zero on any failure), not by whether the tail of its output looks green.
|
|
262
294
|
- `!bash "${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/bin/verify_stack.sh" .claude/config/stack.yaml`
|
|
263
295
|
— **your repo's stack** reachability (pass the repo stack path explicitly so it's unambiguous
|
|
264
296
|
which config was checked). An unreachable tool slot is **not** fatal at setup time; print its
|
|
@@ -278,6 +310,11 @@ Only on explicit confirmation, execute — **source of truth first, derived file
|
|
|
278
310
|
- **The punch list** — one entry per skipped round, each naming its re-entry command
|
|
279
311
|
(`/setup role` for round 5, `/setup policies` for round 6). Deferring must be trackable;
|
|
280
312
|
"took defaults" must never be indistinguishable from "chose".
|
|
313
|
+
- **`project.assignee_dir`, in one line — what the key is for, not a warning.** It is the
|
|
314
|
+
last-resort owner subdir under `tickets/` for a repo with no `people/` roster. Once a roster
|
|
315
|
+
exists, the owner of new work is whoever `whoami` resolves, and a person it does not
|
|
316
|
+
recognize is a stop (`/setup --teammate`) rather than a fall-back to this key — so say that,
|
|
317
|
+
and never describe it as something setup is refusing to touch.
|
|
281
318
|
- **Email, when round 4 recorded delivery:** say plainly that email is **configured but not
|
|
282
319
|
yet activated** — the commented target block holds the answers, and nothing will send until
|
|
283
320
|
someone deliberately activates it: convert the chat slot to `targets:` form with a declared
|
|
@@ -296,4 +333,6 @@ Only on explicit confirmation, execute — **source of truth first, derived file
|
|
|
296
333
|
ticket PR references rules/adapters absent from the repo's history. Offer a commit (e.g.
|
|
297
334
|
`chore: initialize ticketwright workspace`). First flag that `stack.yaml` may hold internal
|
|
298
335
|
identifiers (tracker site, warehouse project/dataset) — config, not secrets, but worth a glance
|
|
299
|
-
before committing to a public repo.
|
|
336
|
+
before committing to a public repo. On a remote created empty (no default branch yet), this
|
|
337
|
+
first push seeds `main` directly — there is nothing to open a PR against — and the PR flow
|
|
338
|
+
starts with the next change; say so rather than colliding with a never-push-to-main rule.
|
|
@@ -21,6 +21,12 @@ it in later" is always a valid answer: write the key as a `# TODO` and keep goin
|
|
|
21
21
|
`verify_stack.sh` names every unset required key as a warning on every run, so a deferred key is a
|
|
22
22
|
tracked choice, not a silent hole.
|
|
23
23
|
|
|
24
|
+
One key deserves a precision note wherever it is asked: a slot's **`mcp:` value must be the
|
|
25
|
+
runtime's exact tool prefix** — the `<name>` in `mcp__<name>__*` — because adapters render tool
|
|
26
|
+
names from it. Tell the person to copy it from a tool name they can see, not from a UI label; a
|
|
27
|
+
friendly name that matches no connected server makes every rendered tool name point at nothing,
|
|
28
|
+
and nothing errors until a skill tries to call one.
|
|
29
|
+
|
|
24
30
|
Never promise a question count, in this file or in any report — a stated number becomes the
|
|
25
31
|
binding constraint on correctness, which is exactly the defect this round structure replaced.
|
|
26
32
|
|
|
@@ -79,8 +79,9 @@ Render `${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/.claude/settings.json.tmpl`
|
|
|
79
79
|
**On a plugin install, also commit a project-scoped enablement.** A plugin can't set its own install
|
|
80
80
|
scope — the *repo* opts in. Merge these two keys
|
|
81
81
|
into the rendered `.claude/settings.json` so the plugin is enabled *for this repo* (committed →
|
|
82
|
-
travels with the repo;
|
|
83
|
-
|
|
82
|
+
travels with the repo; it survives the original author leaving). Registering the marketplace is not
|
|
83
|
+
installing the plugin — a teammate who opens and trusts the repo gets the marketplace clone, then
|
|
84
|
+
runs the install themselves (Track 2). It also refreshes
|
|
84
85
|
itself:
|
|
85
86
|
|
|
86
87
|
```json
|
|
@@ -38,11 +38,34 @@ commits `/ship` makes. If either is unset, have the person set them now — repo
|
|
|
38
38
|
re-run step 0): the identity recorded is now one this machine actually resolves by.
|
|
39
39
|
|
|
40
40
|
## 1 · Install prerequisites
|
|
41
|
-
|
|
41
|
+
**First, the two that make everything after them pointless.** Both probes are read-only:
|
|
42
|
+
|
|
43
|
+
- **Is this a clone?** `!git rev-parse --show-toplevel` — a non-zero exit means there is no
|
|
44
|
+
repository here. **Halt**: "There is no `.git` in this folder. If it came from a Download-ZIP
|
|
45
|
+
button (the folder name usually ends in `-main`), Ticketwright cannot branch, commit, or open a
|
|
46
|
+
PR from it. Clone the repo instead — `git clone <the repository's URL>` — then re-run this
|
|
47
|
+
inside the clone."
|
|
48
|
+
- **Is the kit installed and usable here?**
|
|
49
|
+
`!python3 "${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR}/bin/plugin_doctor.py" --json` — a
|
|
50
|
+
read-only pass over the install prerequisites; it installs nothing and makes no network call.
|
|
51
|
+
Report every finding that is not `ok` with its `fix` lines **verbatim** — they are exact
|
|
52
|
+
commands. A `fail` on `scope_supported` (the agent CLI is too old to install a plugin for one
|
|
53
|
+
repo), `repo_install` (nothing is installed for this repository) or `install_payload` (the
|
|
54
|
+
install record points at a directory that does not exist) is a **halt**: none of it is fixable
|
|
55
|
+
by anything this flow writes, and the fix text names the route out — including the in-session
|
|
56
|
+
install and the update command for how the CLI was installed. `warn`/`unknown` findings are
|
|
57
|
+
reported and the flow continues; on a vendored or pip install the install checks answer
|
|
58
|
+
`unknown`, which is the expected answer there. If the script is absent (an older kit copy), say
|
|
59
|
+
so in one line and carry on.
|
|
60
|
+
|
|
61
|
+
Then check the rest: `for c in <the CLIs named by the configured tool slots> yq jq git; do
|
|
42
62
|
command -v $c >/dev/null && echo "✓ $c" || echo "✗ $c (install)"; done`. For each missing tool give
|
|
43
63
|
the install command (Homebrew / winget / apt as appropriate). Scope note: `yq` is needed only by
|
|
44
64
|
the kit's own `selftest.sh` (step 5 runs it once, as a kit-integrity check) — no skill in a
|
|
45
|
-
configured repo invokes it day to day, so a missing `yq` blocks that one check, nothing else.
|
|
65
|
+
configured repo invokes it day to day, so a missing `yq` blocks that one check, nothing else. When
|
|
66
|
+
`yq_present` is not `ok`, print the doctor's platform install command and **offer to run it now**,
|
|
67
|
+
before step 5 needs it — and say what step 5 costs: several minutes, longer than a typical tool
|
|
68
|
+
timeout, judged by its **exit code**, not by how green the tail of its output looks.
|
|
46
69
|
|
|
47
70
|
## 2 · Authenticate each configured tool
|
|
48
71
|
For every configured tool slot, open its adapter's `auth:` notes and walk the person through
|
|
@@ -18,19 +18,30 @@ brief, nothing else. Follow [priming.md](priming.md) § Recall. Useful mid-sessi
|
|
|
18
18
|
this before?", "which tickets touched VW_X?").
|
|
19
19
|
|
|
20
20
|
## Phase 0 — Resolve & preflight (halt-on-fail)
|
|
21
|
-
0. **
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- `
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
21
|
+
0. **Read the merged config first — it is what decides WHO** — `bash "${CLAUDE_PLUGIN_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || echo .)}/bin/tw" effective_config.py --json`,
|
|
22
|
+
never raw `stack.yaml`. It carries `project.*`, `seams.tracker`, `seams.vcs` — and it settles the
|
|
23
|
+
owner **mechanically**, in one field, so no skill re-derives the rule. If the team config is
|
|
24
|
+
missing, say so and offer `/setup` — don't scaffold blind. Branch on **`owner_source`**, never on
|
|
25
|
+
a `people/` listing of your own: a roster can live entirely in
|
|
26
|
+
`$XDG_CONFIG_HOME/ticketwright/people/` and never appear in this repo, and only the resolver
|
|
27
|
+
looks in both homes — "no `people/*.yaml` here" is not the same question.
|
|
28
|
+
- `resolved` — proceed; `owner` is this person and owns everything below.
|
|
29
|
+
- `unbound` — **HARD STOP here, before any ticket path is rendered.** Say:
|
|
30
|
+
"I can't tell who you are: `people/<id>.yaml` is a placeholder (or no `people/` entry matches
|
|
31
|
+
this machine's identity). Run `/setup --teammate` first — it asks who you are, binds it, and
|
|
32
|
+
sets up your machine." Do **not** fall back to `project.assignee_dir`: with a roster present
|
|
33
|
+
that key names a COLLEAGUE, and their `tickets/<owner>/` folder is exactly where an unbound
|
|
34
|
+
teammate's work silently lands. Never infer an owner from a name.
|
|
35
|
+
- `assignee_dir_fallback` — proceed with `owner`: there is no roster in either home, so
|
|
36
|
+
`project.assignee_dir` is the documented last resort for repos that predate owner routing.
|
|
37
|
+
- `none` — stop: no roster and no `assignee_dir`. Offer `/setup`.
|
|
38
|
+
Read `owner`, never `project.assignee_dir` directly.
|
|
39
|
+
1. **Then show who that is** — `bash "${CLAUDE_PLUGIN_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || echo .)}/bin/tw" whoami.py`,
|
|
40
|
+
and show its one-line "Working as …" display. This is the display-and-binding step; the routing
|
|
41
|
+
decision was already made in step 0, and whoami never overrides it. Two statuses still change
|
|
42
|
+
what you do next: `ambiguous` — ask which person it is; never rank or pick, and step 0's hard
|
|
43
|
+
stop stands until they answer. `conflict` — proceed as the machine-pinned person and surface the
|
|
44
|
+
warning line verbatim.
|
|
34
45
|
2. **Verify** the tracker + vcs seams (run their `verify` commands). If one is unreachable, print
|
|
35
46
|
that adapter's `auth` notes and offer to continue **local-only** (workspace + context still work;
|
|
36
47
|
tracker fetch is skipped) — degrade, don't die.
|
|
@@ -44,10 +55,11 @@ this before?", "which tickets touched VW_X?").
|
|
|
44
55
|
## Phase 1 — Resume, don't restart
|
|
45
56
|
4. Render `project.ticket_path` → the ticket dir, filling `{assignee}` with the **locator's owner**
|
|
46
57
|
(the step-0 resolved person for new or bare-id work — never the static `project.assignee_dir`,
|
|
47
|
-
except through step 0's
|
|
48
|
-
`final_deliverables/`, check `git log --oneline -10` + `git status`,
|
|
49
|
-
what remains, re-fetch the ticket for new comments, then **skip to
|
|
50
|
-
person's ticket (locator owner ≠ resolved person) is fine — say so
|
|
58
|
+
except through step 0's `assignee_dir_fallback` last resort). If the dir exists: read its
|
|
59
|
+
`README.md`, list `final_deliverables/`, check `git log --oneline -10` + `git status`, and
|
|
60
|
+
summarize what's done and what remains, re-fetch the ticket for new comments, then **skip to
|
|
61
|
+
Phase 3**. Resuming another person's ticket (locator owner ≠ resolved person) is fine — say so
|
|
62
|
+
out loud.
|
|
51
63
|
|
|
52
64
|
## Phase 2 — Workspace (new ticket)
|
|
53
65
|
5. **Branch** via the vcs adapter, named `<id>`, off `seams.vcs.default_branch` — or a **worktree**
|
|
@@ -4,6 +4,79 @@ All notable changes to this project are documented here. Format loosely follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/); this project uses semantic-ish versioning.
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
## [4.0.2] — 2026-09-03
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **`bin/plugin_doctor.py` — every install state gets a name and a fix.** Onboarding onto a repo that
|
|
11
|
+
already carries the committed enablement failed in ways nothing in the kit could describe: a CLI too
|
|
12
|
+
old to accept `--scope` (Claude Code 2.0.x has neither `--scope` nor `plugin list`), a marketplace
|
|
13
|
+
registered with nothing installed, a global install nobody meant, an install record whose
|
|
14
|
+
`installPath` was never created (the install reports success, re-running it is a no-op), and a
|
|
15
|
+
"Download ZIP" folder with no `.git`. The doctor checks all of that in one command — plus `yq`, git
|
|
16
|
+
identity, the update channel to update through, and whether the installed version is behind the
|
|
17
|
+
marketplace catalog — and prints the fix for each, human-readable or `--json`. It runs from the
|
|
18
|
+
marketplace clone before anything is installed
|
|
19
|
+
(`python3 ~/.claude/plugins/marketplaces/ticketwright/bin/plugin_doctor.py`, a fork substitutes its
|
|
20
|
+
own marketplace name) and through `bin/tw` afterwards. Stdlib only, no network, no writes; it never
|
|
21
|
+
runs an install, and it reuses `update_notice.py` so its upgrade fix is the same string the session
|
|
22
|
+
banner prints. `/setup` runs it at preflight and halts on the states nothing setup writes can fix.
|
|
23
|
+
- **Install prerequisites an agent can read before the plugin loads.** README Track 2 and
|
|
24
|
+
`templates/AGENTS.md.tmpl` carry the same fourteen checks in the same order as the doctor, each
|
|
25
|
+
tagged with a `doctor-check` marker; selftest pins the set and order against the doctor's own check
|
|
26
|
+
list, so the three surfaces cannot drift.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- **The joiner install no longer lands at user scope.** README Track 2, `docs/troubleshooting.md` and
|
|
30
|
+
the rendered `AGENTS.md` all gave the bare `claude plugin install ticketwright@ticketwright`, which
|
|
31
|
+
defaults to `--scope user` — installing Ticketwright for every repo on the machine while the repo
|
|
32
|
+
itself got nothing. All three now give the `--scope project` pair, run from the repository root
|
|
33
|
+
(a project-scope install keys to the session's directory, claude-code#82830), with the in-app
|
|
34
|
+
`/plugin install` → Project-scope route as the fallback for a CLI too old for the flag.
|
|
35
|
+
- **The "teammates are prompted to install" claim is gone.** It was in the README, `setup/scaffold.md`,
|
|
36
|
+
`.claude/settings.json.tmpl` and `templates/AGENTS.md.tmpl`, and it is not what happens: registering
|
|
37
|
+
the marketplace is not installing the plugin, and the documented behavior (Claude Code 2.1.195 and
|
|
38
|
+
later report the plugin as not installed and show the install command; older builds say nothing) is
|
|
39
|
+
now what those four files say.
|
|
40
|
+
- **"Restart" says what it means.** Every restart instruction now names `/reload-plugins` or a new
|
|
41
|
+
session first, then a full quit of the Claude app (Cmd+Q, or File → Exit) if the skills are still
|
|
42
|
+
absent — a new chat inside the running app is not a restart.
|
|
43
|
+
- **`bin/update_notice.py` recognises a `local` install row** (the desktop app writes one) and emits
|
|
44
|
+
the uninstall/reinstall pair at the scope the record actually carries, instead of assuming
|
|
45
|
+
`--scope project`.
|
|
46
|
+
- **An unbound teammate no longer writes into someone else's folder.** A `people/<id>.yaml` placeholder
|
|
47
|
+
with no identities resolved to the project's `assignee_dir`, so a first ticket opened before
|
|
48
|
+
`/setup --teammate` landed under another person's directory. The ticket front door now halts and
|
|
49
|
+
names the fix.
|
|
50
|
+
|
|
51
|
+
### Changed
|
|
52
|
+
- **`/setup` preflight order:** git repo → the doctor's findings → `yq` (with the platform install
|
|
53
|
+
command offered before the self-test needs it) → identity. A ZIP folder or a broken install is
|
|
54
|
+
reported before setup writes anything, since nothing setup writes would repair it.
|
|
55
|
+
|
|
56
|
+
### Docs
|
|
57
|
+
- `docs/troubleshooting.md`: cause 2 is now "Your Claude Code CLI is too old" with per-channel update
|
|
58
|
+
commands; a new cause covers an install record with no payload, including the safety conditions on
|
|
59
|
+
the copy-the-clone recovery; the upgrade table gains a `local`-scope row; a new block names the three
|
|
60
|
+
ways to run the doctor.
|
|
61
|
+
|
|
62
|
+
## [4.0.1] — 2026-09-02
|
|
63
|
+
|
|
64
|
+
### Fixed
|
|
65
|
+
- **The kit-integrity selftest passes on a plugin install.** Section 31 ran `bin/tw` from inside the
|
|
66
|
+
kit's own tree and expected the kit root — right only when the kit is a git repo, so on a plugin
|
|
67
|
+
install (a cache, not a repo) two assertions failed for a reason no user ever meets. The test now
|
|
68
|
+
builds a git project and runs from a ticket subdirectory, which is the real scenario; `bin/tw`
|
|
69
|
+
itself was already correct there.
|
|
70
|
+
- **A verify can no longer hang setup.** `verify_stack.sh` runs each slot's verify under a wall-clock
|
|
71
|
+
cap (`VERIFY_TIMEOUT`, default 30s) and reports a timeout as "appears to need interactive auth"
|
|
72
|
+
— a browser-SSO warehouse connection used to block the whole check with no output.
|
|
73
|
+
|
|
74
|
+
### Docs
|
|
75
|
+
- `/setup`: fall back to the current local branch when `refs/remotes/origin/HEAD` is unset (an
|
|
76
|
+
unpushed repo); expect `selftest.sh` to take several minutes and judge it by exit code; on a
|
|
77
|
+
remote created empty, the scaffold's first push seeds `main` and the PR flow starts with the next
|
|
78
|
+
change; a slot's `mcp:` value must be the runtime's exact tool prefix (`mcp__<name>__*`).
|
|
79
|
+
|
|
7
80
|
## [4.0.0] — 2026-09-02
|
|
8
81
|
|
|
9
82
|
Breaking: `/productize` is now `/skillify`, and `templates/productized-skill/` is now
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ticketwright
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.2
|
|
4
4
|
Summary: Tool-agnostic AI layer for ticket-driven work repos: prior-art recall, object reverse-index, deep QC, and a self-maintaining ticket index. Stdlib-only, no vector store.
|
|
5
5
|
Project-URL: Homepage, https://github.com/kyle-chalmers/ticketwright
|
|
6
6
|
Project-URL: Repository, https://github.com/kyle-chalmers/ticketwright
|
|
@@ -169,9 +169,10 @@ personal install, or another repo's), `marketplace add … --scope project` prin
|
|
|
169
169
|
declared in project settings" — expected, not an error: the cached marketplace is reused and the
|
|
170
170
|
project-scoped declaration still lands in this repo's settings.
|
|
171
171
|
|
|
172
|
-
**2 ·
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
**2 · Reload the plugin, or restart.** Plugin skills load at session start, so installing and
|
|
173
|
+
running `/setup` in the same session silently fails: the command simply doesn't exist yet. Run
|
|
174
|
+
`/reload-plugins` or start a new session. If the commands still do not appear, fully quit the Claude
|
|
175
|
+
app (Cmd+Q on macOS, File → Exit on Windows/Linux) and relaunch — a new chat is not a restart.
|
|
175
176
|
|
|
176
177
|
*Check:* `/ticketwright:setup` shows up in the new session's command list.
|
|
177
178
|
|
|
@@ -253,20 +254,124 @@ start, but does NOT install the plugin.** Verified live: a teammate's `installed
|
|
|
253
254
|
stayed `{}` across restarts until the manual install in step 2. Skip step 2 and
|
|
254
255
|
`/ticketwright:setup` is not a command that exists.
|
|
255
256
|
|
|
256
|
-
|
|
257
|
+
#### If you are the agent helping someone install — read this first
|
|
258
|
+
|
|
259
|
+
One command answers most of what follows. The marketplace clone lands on disk as soon as the person
|
|
260
|
+
opens and trusts the repo — before anything is installed — so this runs at the moment nothing else
|
|
261
|
+
does:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
python3 ~/.claude/plugins/marketplaces/ticketwright/bin/plugin_doctor.py
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
That path names the `ticketwright` marketplace; a fork substitutes its own marketplace name. The
|
|
268
|
+
doctor prints one line per check below, with the fix for each, and takes `--json` for a
|
|
269
|
+
machine-readable report. Once the plugin is installed the same checks run as
|
|
270
|
+
`bash "${CLAUDE_PLUGIN_ROOT:-.}/bin/tw" plugin_doctor.py`.
|
|
271
|
+
|
|
272
|
+
The checks, in the order the doctor runs them:
|
|
273
|
+
|
|
274
|
+
1. **A clone, not a downloaded ZIP.** <!-- doctor-check: git_clone -->
|
|
275
|
+
`ls -d .git`. A "Download ZIP" folder (named `<repo>-main`, no `.git`) cannot branch, commit, or
|
|
276
|
+
open a PR. Fix: `git clone <repo url>` and work in the clone.
|
|
277
|
+
2. **You are at the repository root.** <!-- doctor-check: cwd_is_root -->
|
|
278
|
+
`git rev-parse --show-toplevel` matches your working directory. A project-scope install keys to
|
|
279
|
+
the session's directory rather than the repo root
|
|
280
|
+
([claude-code#82830](https://github.com/anthropics/claude-code/issues/82830)), so run both
|
|
281
|
+
install commands from the root.
|
|
282
|
+
3. **The `claude` CLI is on PATH.** <!-- doctor-check: claude_on_path -->
|
|
283
|
+
`command -v claude`. Missing: install Claude Code and reopen the terminal. The in-app route
|
|
284
|
+
below needs no terminal at all.
|
|
285
|
+
4. **Which version that CLI is.** <!-- doctor-check: claude_version -->
|
|
286
|
+
`claude --version`. Reported, not judged: from Claude Code 2.1.195 the app itself reports a
|
|
287
|
+
repo's plugin as not installed and shows the install command; older builds say nothing, which is
|
|
288
|
+
why this checklist exists.
|
|
289
|
+
5. **That CLI understands `--scope`.** <!-- doctor-check: scope_supported -->
|
|
290
|
+
`claude plugin install --help` mentions `--scope`. If it does not, the CLI is too old for either
|
|
291
|
+
install command — use the in-app route below, then update it.
|
|
292
|
+
6. **How that CLI was installed.** <!-- doctor-check: install_channel -->
|
|
293
|
+
`readlink -f "$(command -v claude)"` says which channel to update through: native installer →
|
|
294
|
+
`claude update`; npm or nvm → `npm install -g @anthropic-ai/claude-code@latest`; Homebrew →
|
|
295
|
+
`brew upgrade claude-code`. An nvm `claude` earlier on PATH shadows a native one; `claude doctor`
|
|
296
|
+
lists conflicting installs.
|
|
297
|
+
7. **The marketplace is registered.** <!-- doctor-check: marketplace_registered -->
|
|
298
|
+
A `ticketwright` entry in `~/.claude/plugins/known_marketplaces.json` whose `installLocation`
|
|
299
|
+
exists on disk. Missing: the first command of the pair below.
|
|
300
|
+
8. **This repo has an install record.** <!-- doctor-check: repo_install -->
|
|
301
|
+
A row in `~/.claude/plugins/installed_plugins.json` whose `projectPath` is this repo.
|
|
302
|
+
Registration never creates one. Fix: the pair below, from the repository root, then restart.
|
|
303
|
+
9. **The install record points at files that exist.** <!-- doctor-check: install_payload -->
|
|
304
|
+
The recorded `installPath` holds a `.claude-plugin/plugin.json`. Seen on Claude Code 2.0.22:
|
|
305
|
+
install prints "Successfully installed" and the directory is never created, so re-running install
|
|
306
|
+
is a no-op. Fix: update the CLI, then
|
|
307
|
+
`claude plugin uninstall ticketwright@ticketwright --scope <the recorded scope>` and install
|
|
308
|
+
again; if uninstall answers "not found", copy the marketplace clone into the recorded path —
|
|
309
|
+
recipe in [`docs/troubleshooting.md`](docs/troubleshooting.md).
|
|
310
|
+
10. **No machine-wide install nobody meant.** <!-- doctor-check: user_install -->
|
|
311
|
+
A row with `scope: "user"` turns Ticketwright on for every repo on the machine. If you meant
|
|
312
|
+
this repo only: `claude plugin uninstall ticketwright@ticketwright --scope user`, then the pair
|
|
313
|
+
below.
|
|
314
|
+
11. **The installed version matches the marketplace catalog.** <!-- doctor-check: catalog_current -->
|
|
315
|
+
Behind means a tagged release has not been picked up; the fix is the uninstall-and-install pair
|
|
316
|
+
the session banner names, at the scope the install record carries.
|
|
317
|
+
12. **`yq` is installed.** <!-- doctor-check: yq_present -->
|
|
318
|
+
`command -v yq`. Needed only by `bin/selftest.sh`, where its absence fails a dozen-plus checks
|
|
319
|
+
from one cause. macOS: `brew install yq`. Linux: your distribution's package. Windows:
|
|
320
|
+
`winget install MikeFarah.yq`.
|
|
321
|
+
13. **Git identity is set.** <!-- doctor-check: git_identity -->
|
|
322
|
+
`git config --get user.name` and `git config --get user.email`. Unset, the first commit fails:
|
|
323
|
+
`git config user.name "…"` and `git config user.email "…"`.
|
|
324
|
+
14. **Restart the right way.** <!-- doctor-check: restart -->
|
|
325
|
+
Printed whenever an install check above is not clean. Run `/reload-plugins` or start a new
|
|
326
|
+
session. If the skills still do not appear, fully quit the Claude app (Cmd+Q on macOS,
|
|
327
|
+
File → Exit on Windows/Linux) and relaunch. A new chat inside the running app is not a restart.
|
|
328
|
+
|
|
329
|
+
The install itself is two commands, run from the repository root:
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
claude plugin marketplace add https://github.com/kyle-chalmers/ticketwright.git --scope project
|
|
333
|
+
claude plugin install ticketwright@ticketwright --scope project
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
When the repo's committed settings already registered the marketplace, the first command prints
|
|
337
|
+
"already on disk — declared in project settings" — expected, not an error. **No terminal, or a CLI
|
|
338
|
+
that rejects `--scope`?** Run `/plugin install ticketwright@ticketwright` in the session and choose
|
|
339
|
+
**Project** scope, or use **+ → Plugins → Add plugin** in the desktop app; both run in the app's own
|
|
340
|
+
engine. Then update the CLI (check 6).
|
|
341
|
+
|
|
342
|
+
*Verify:* `claude plugin list` shows `ticketwright@ticketwright … enabled`, and
|
|
343
|
+
`/ticketwright:setup` appears in the next session's command list. `bin/selftest.sh` takes several
|
|
344
|
+
minutes — judge it by its exit code, not by how long it has been running. Anything still
|
|
345
|
+
unexplained: [`docs/troubleshooting.md`](docs/troubleshooting.md).
|
|
346
|
+
|
|
347
|
+
**1 · `git clone` the repo and open it in Claude Code** (trust the workspace when prompted). Use a
|
|
348
|
+
clone, not GitHub's "Download ZIP" — a `<repo>-main` folder with no `.git` cannot branch, commit, or
|
|
349
|
+
open a PR.
|
|
257
350
|
|
|
258
351
|
*Check:* `.claude/config/stack.yaml` exists — that's the team config Track 1 committed.
|
|
259
352
|
|
|
260
|
-
**2 · Install the plugin explicitly
|
|
353
|
+
**2 · Install the plugin explicitly**, from the repository root:
|
|
261
354
|
|
|
262
355
|
```bash
|
|
263
|
-
claude plugin
|
|
356
|
+
claude plugin marketplace add https://github.com/kyle-chalmers/ticketwright.git --scope project
|
|
357
|
+
claude plugin install ticketwright@ticketwright --scope project
|
|
264
358
|
```
|
|
265
359
|
|
|
266
|
-
|
|
360
|
+
Both commands default to `--scope user`, which would install Ticketwright for every repo on your
|
|
361
|
+
machine instead of this one. The marketplace is usually registered already from the committed
|
|
362
|
+
settings, so the first command prints "already on disk — declared in project settings" — expected,
|
|
363
|
+
not an error. If your CLI rejects `--scope`, it is too old: run `/plugin install
|
|
364
|
+
ticketwright@ticketwright` in the session and choose **Project** scope (or use **+ → Plugins → Add
|
|
365
|
+
plugin** in the desktop app), then update the CLI — see the checklist above.
|
|
366
|
+
|
|
367
|
+
*Check:* `claude plugin list` shows `ticketwright@ticketwright … enabled`. If your CLI answers
|
|
368
|
+
`unknown command 'list'` or `unknown option '--scope'`, it is too old — Claude Code 2.0.x has
|
|
369
|
+
neither; see the checklist above.
|
|
267
370
|
|
|
268
|
-
**3 ·
|
|
269
|
-
|
|
371
|
+
**3 · Reload the plugin, or restart.** Plugin skills load at session start; installing and running
|
|
372
|
+
`/setup` in the same session silently fails. Run `/reload-plugins` or start a new session. If the
|
|
373
|
+
commands still do not appear, fully quit the Claude app (Cmd+Q on macOS, File → Exit on
|
|
374
|
+
Windows/Linux) and relaunch — a new chat is not a restart.
|
|
270
375
|
|
|
271
376
|
*Check:* `/ticketwright:setup` shows up in the new session's command list.
|
|
272
377
|
|
|
@@ -373,9 +478,10 @@ means later ticket PRs reference rules that aren't in the repo's history.
|
|
|
373
478
|
### Project-scoped by default
|
|
374
479
|
|
|
375
480
|
A plugin can't set its own install scope — the **repo** does. `--scope project` writes the enablement
|
|
376
|
-
into the repo's `.claude/settings.json`, so it travels *with the repo
|
|
377
|
-
|
|
378
|
-
|
|
481
|
+
into the repo's `.claude/settings.json`, so it travels *with the repo*, and it keeps working after
|
|
482
|
+
the person who set it up moves on. Registering the marketplace is not installing the plugin — a
|
|
483
|
+
teammate who opens and trusts the repo gets the marketplace clone, then runs the install themselves
|
|
484
|
+
(Track 2). Commit the file. This is what the two Track 1
|
|
379
485
|
install commands produce, plus the one key they don't write:
|
|
380
486
|
|
|
381
487
|
```json
|