tcw-cli 2.0.2__tar.gz → 2.1.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.
- {tcw_cli-2.0.2/tcw_cli.egg-info → tcw_cli-2.1.2}/PKG-INFO +201 -18
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/README.md +200 -17
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/pyproject.toml +8 -1
- tcw_cli-2.1.2/tcw/__init__.py +1 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/capabilities/cli.py +19 -1
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/cli.py +9 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/store/base.py +205 -9
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/store/fs.py +244 -31
- tcw_cli-2.1.2/tcw/tracker/__init__.py +12 -0
- tcw_cli-2.1.2/tcw/tracker/claim.py +183 -0
- tcw_cli-2.1.2/tcw/tracker/intake.py +373 -0
- tcw_cli-2.1.2/tcw/tracker/jira.py +315 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/validate.py +43 -9
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/cli.py +408 -15
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/recursion.py +16 -7
- {tcw_cli-2.0.2 → tcw_cli-2.1.2/tcw_cli.egg-info}/PKG-INFO +201 -18
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw_cli.egg-info/SOURCES.txt +22 -0
- tcw_cli-2.1.2/tests/test_capabilities_rm.py +406 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_capabilities_sidecar.py +18 -5
- tcw_cli-2.1.2/tests/test_committed_paths.py +38 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_documented_cli_surface.py +18 -3
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_environment_hardness.py +130 -0
- tcw_cli-2.1.2/tests/test_eval_coverage.py +48 -0
- tcw_cli-2.1.2/tests/test_eval_files_changed.py +177 -0
- tcw_cli-2.1.2/tests/test_eval_fixture.py +316 -0
- tcw_cli-2.1.2/tests/test_eval_grading.py +234 -0
- tcw_cli-2.1.2/tests/test_eval_runner.py +273 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_external_work_store.py +109 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_non_git_writes.py +73 -3
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_plugin_manifests.py +1 -1
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_recursion.py +10 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_remote_session_setup.py +65 -11
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_scaffold.py +6 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_session_bootstrap.py +1 -1
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_skill_lifecycle_parity.py +5 -1
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_store_editor.py +30 -22
- tcw_cli-2.1.2/tests/test_tracker_absent.py +163 -0
- tcw_cli-2.1.2/tests/test_tracker_binding.py +250 -0
- tcw_cli-2.1.2/tests/test_tracker_claim.py +247 -0
- tcw_cli-2.1.2/tests/test_tracker_claimability.py +220 -0
- tcw_cli-2.1.2/tests/test_tracker_cli.py +258 -0
- tcw_cli-2.1.2/tests/test_tracker_client.py +460 -0
- tcw_cli-2.1.2/tests/test_tracker_config.py +191 -0
- tcw_cli-2.1.2/tests/test_tracker_import.py +354 -0
- tcw_cli-2.1.2/tests/test_tracker_link.py +192 -0
- tcw_cli-2.1.2/tests/test_tracker_replay.py +147 -0
- tcw_cli-2.1.2/tests/test_tracker_validate.py +178 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_validate.py +99 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_work.py +23 -0
- tcw_cli-2.1.2/tests/test_work_tags.py +398 -0
- tcw_cli-2.0.2/tcw/__init__.py +0 -1
- tcw_cli-2.0.2/tests/test_work_tags.py +0 -182
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/LICENSE +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/setup.cfg +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/capabilities/__init__.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/refs.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/serve/__init__.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/serve/dist/client/assets/index-CXNiOIeg.css +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/serve/dist/client/assets/index-Dz5B7M8G.js +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/serve/dist/client/index.html +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/serve/dist/client/theme-init.js +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/serve/dist/server.cjs +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/serve/runtime.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/stdin.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/store/__init__.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/store/checkouts.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/store/project.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/taxonomy/__init__.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/taxonomy/cli.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/__init__.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/generate.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/hooks.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/projection.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/prompts/implement.md +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/prompts/inbox.md +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/prompts/plan.md +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/prompts/postmortem.md +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/prompts/request.md +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/prompts/spec.md +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/prompts/verify.md +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/resolve.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw/work/templates.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw_cli.egg-info/dependency_links.txt +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw_cli.egg-info/entry_points.txt +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw_cli.egg-info/requires.txt +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tcw_cli.egg-info/top_level.txt +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_body_prompt.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_capabilities.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_capabilities_federation.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_capabilities_reset.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_capability_ref_wording.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_cut_version.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_documentation_config.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_documentation_prompt.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_documentation_sync_wiring.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_epic_completable.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_falsification_rule.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_generate_hook.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_inbox_title.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_lifecycle_baseline.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_lifecycle_hooks.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_lifecycle_inert.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_lifecycle_policy.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_lifecycle_validation.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_multiproject.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_project_overrides.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_project_registry.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_projection.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_prompt_fallback.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_qualified_ref.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_refs.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_repo_lifecycle.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_resolve.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_retention.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_serve.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_serve_descendants.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_serve_projection.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_serve_resolve.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_serve_runtime.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_serve_write.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_shipped_prompts.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_show_json.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_skill_flow.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_smoke.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_stage_verb.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_status_parity.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_stdin.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_stdin_cli.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_store_bounds.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_store_nodes.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_store_provisioning.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_store_publication.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_subprocess_stdin.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_taxonomy.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_tombstone.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_unpushed_version_script.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_validate_target.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_work_autocommit.py +0 -0
- {tcw_cli-2.0.2 → tcw_cli-2.1.2}/tests/test_work_review.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tcw-cli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.2
|
|
4
4
|
Summary: Taxonomy · Capabilities · Work — a storage-abstracted framework for describing and evolving a software project.
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -229,6 +229,28 @@ They link by one-directional pointers — a capability names the taxonomy terms
|
|
|
229
229
|
involves, a work item names the capability it changes — and never copy each
|
|
230
230
|
other's content.
|
|
231
231
|
|
|
232
|
+
## Contents
|
|
233
|
+
|
|
234
|
+
- [The problem](#the-problem)
|
|
235
|
+
- [What it looks like](#what-it-looks-like)
|
|
236
|
+
- [Why many repositories is the case it is built for](#why-many-repositories-is-the-case-it-is-built-for)
|
|
237
|
+
- [What it deliberately refuses](#what-it-deliberately-refuses)
|
|
238
|
+
- [What adopting it costs](#what-adopting-it-costs)
|
|
239
|
+
- [Who it's for](#who-its-for)
|
|
240
|
+
- [Storage abstraction (the prime directive)](#storage-abstraction-the-prime-directive)
|
|
241
|
+
- [Install](#install)
|
|
242
|
+
- [As a plugin (recommended)](#as-a-plugin-recommended)
|
|
243
|
+
- [As a Python package](#as-a-python-package)
|
|
244
|
+
- [In a cloud environment](#in-a-cloud-environment)
|
|
245
|
+
- [Quickstart](#quickstart)
|
|
246
|
+
- [Working from your Jira tickets](#working-from-your-jira-tickets)
|
|
247
|
+
- [Documentation](#documentation)
|
|
248
|
+
- [Skills — the judgment layer](#skills--the-judgment-layer)
|
|
249
|
+
- [Reading a lifecycle stage](#reading-a-lifecycle-stage)
|
|
250
|
+
- [Review agents and slash commands](#review-agents-and-slash-commands)
|
|
251
|
+
- [Status](#status)
|
|
252
|
+
- [Further reading](#further-reading)
|
|
253
|
+
|
|
232
254
|
---
|
|
233
255
|
|
|
234
256
|
## The problem
|
|
@@ -407,8 +429,9 @@ Or, in the Claude **web app** or **desktop app**, open the plugin directory, add
|
|
|
407
429
|
by installing `tcw-cli` from PyPI with `pipx`, so one installed mid-session
|
|
408
430
|
cannot run until the next one begins. That first session needs network access. It
|
|
409
431
|
installs over an existing `pipx install tcw-cli` rather than beside it, and
|
|
410
|
-
leaves a development checkout (`pip install -e .`) alone.
|
|
411
|
-
|
|
432
|
+
leaves a development checkout (`pip install -e .`) alone. If `tcw` goes missing
|
|
433
|
+
anyway, `pipx install tcw-cli` is the whole fix — the **`tcw-plugin`** skill
|
|
434
|
+
carries the cases where it is not.
|
|
412
435
|
|
|
413
436
|
In **Codex** (skills only, no slash commands):
|
|
414
437
|
|
|
@@ -439,6 +462,89 @@ additionally requires **Node.js ≥ 22.12**; every other command is Python-only.
|
|
|
439
462
|
Released wheels carry the prebuilt web assets, so there is no frontend build step
|
|
440
463
|
and no network needed after install.
|
|
441
464
|
|
|
465
|
+
### In a cloud environment
|
|
466
|
+
|
|
467
|
+
A cloud agent session — Claude Code on the web, a Codex container, a CI job —
|
|
468
|
+
starts from a clean image and is thrown away when it ends, so a `tcw` you install
|
|
469
|
+
by hand is gone by the next one. Install it **from your repository**, with a
|
|
470
|
+
session-start hook, and every session gets it without anyone remembering to.
|
|
471
|
+
|
|
472
|
+
Add a script to your repository:
|
|
473
|
+
|
|
474
|
+
```sh
|
|
475
|
+
#!/usr/bin/env bash
|
|
476
|
+
# Make `tcw` available in a disposable agent container.
|
|
477
|
+
# Exit 0 on every path — a session must start even when this cannot finish.
|
|
478
|
+
set -u
|
|
479
|
+
|
|
480
|
+
command -v tcw >/dev/null 2>&1 && exit 0
|
|
481
|
+
|
|
482
|
+
# pipx where it exists; otherwise install into the container's own interpreter.
|
|
483
|
+
# That is the right answer *here* and nowhere else: the container is disposable
|
|
484
|
+
# and single-purpose, so there is no user environment to damage.
|
|
485
|
+
if command -v pipx >/dev/null 2>&1; then
|
|
486
|
+
pipx install tcw-cli >/dev/null 2>&1 || echo "tcw: pipx install tcw-cli failed"
|
|
487
|
+
elif ! python3 -m pip install tcw-cli >/dev/null 2>&1 &&
|
|
488
|
+
! python3 -m pip install tcw-cli --break-system-packages >/dev/null 2>&1; then
|
|
489
|
+
echo "tcw: pip install tcw-cli failed — the tcw CLI is not available."
|
|
490
|
+
fi
|
|
491
|
+
|
|
492
|
+
# An install that landed outside PATH is installed and unusable. $CLAUDE_ENV_FILE
|
|
493
|
+
# is the harness's own channel for repairing that.
|
|
494
|
+
if ! command -v tcw >/dev/null 2>&1 && [ -n "${CLAUDE_ENV_FILE:-}" ]; then
|
|
495
|
+
userbin="$(python3 -m site --user-base 2>/dev/null)/bin"
|
|
496
|
+
[ -x "$userbin/tcw" ] && echo "export PATH=\"$userbin:\$PATH\"" >>"$CLAUDE_ENV_FILE"
|
|
497
|
+
fi
|
|
498
|
+
|
|
499
|
+
exit 0
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
Then wire it to `SessionStart` in your repository's `.claude/settings.json`:
|
|
503
|
+
|
|
504
|
+
```json
|
|
505
|
+
{
|
|
506
|
+
"hooks": {
|
|
507
|
+
"SessionStart": [
|
|
508
|
+
{
|
|
509
|
+
"hooks": [
|
|
510
|
+
{
|
|
511
|
+
"type": "command",
|
|
512
|
+
"command": "\"${CLAUDE_PROJECT_DIR}\"/scripts/tcw_session_setup.sh"
|
|
513
|
+
}
|
|
514
|
+
]
|
|
515
|
+
}
|
|
516
|
+
]
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
Three things make the difference between a hook that helps and one that wastes a
|
|
522
|
+
session:
|
|
523
|
+
|
|
524
|
+
- **Exit 0 on every path, and print only on failure.** A hook that fails the
|
|
525
|
+
session start over a missing CLI has cost more than the CLI was worth.
|
|
526
|
+
- **Print to stdout.** Claude Code adds a `SessionStart` hook's stdout to the
|
|
527
|
+
agent's context, where it will be read; stderr becomes a transcript notice
|
|
528
|
+
nobody sees.
|
|
529
|
+
- **Check for `tcw` first.** The hook runs every session, including the ones
|
|
530
|
+
where a previous install is still there.
|
|
531
|
+
|
|
532
|
+
**If your work store lives in another repository**, the container holds only the
|
|
533
|
+
repository it cloned, so the board is declared but absent. Run `tcw provision`
|
|
534
|
+
after the install — it obtains what the checkout does not have, and does nothing
|
|
535
|
+
on a machine that already holds it. See
|
|
536
|
+
[Working across repositories](docs/guide/multi-repo.md).
|
|
537
|
+
|
|
538
|
+
Installing the **plugin** in such a session is a separate step from installing the
|
|
539
|
+
CLI, and only needed where the harness does not carry your plugins in: append
|
|
540
|
+
`claude plugin marketplace add brocef/TCW` and `claude plugin install tcw@tcw` to
|
|
541
|
+
the same script, guarded on `command -v claude`.
|
|
542
|
+
|
|
543
|
+
This repository's own [`scripts/remote_session_setup.sh`](scripts/remote_session_setup.sh)
|
|
544
|
+
is the same pattern written for a _contributor_ rather than a user — it installs
|
|
545
|
+
the checkout with `pip install -e` instead of the release from PyPI, and installs
|
|
546
|
+
the plugin from the checkout too. Read it as the worked example.
|
|
547
|
+
|
|
442
548
|
## Quickstart
|
|
443
549
|
|
|
444
550
|
```sh
|
|
@@ -464,6 +570,79 @@ studies your code, proposes a first draft, refines it with you, and writes it.
|
|
|
464
570
|
|
|
465
571
|
---
|
|
466
572
|
|
|
573
|
+
## Working from your Jira tickets
|
|
574
|
+
|
|
575
|
+
A project can name the Jira Cloud site it uses, read its tickets, and take one as
|
|
576
|
+
a work item.
|
|
577
|
+
|
|
578
|
+
```sh
|
|
579
|
+
tcw work tracker list # tickets the configured query selects
|
|
580
|
+
tcw work tracker show ENG-482 # one ticket, and whether it is yours to take
|
|
581
|
+
tcw work tracker import ENG-482 # take the ticket and get a work item for it
|
|
582
|
+
tcw work tracker link <slug> ENG-482 # take it for an item you already have
|
|
583
|
+
tcw work tracker unlink <slug> --reason "wrong ticket"
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
Configuration goes in the node's `tcw-config.yaml`:
|
|
587
|
+
|
|
588
|
+
```yaml
|
|
589
|
+
work:
|
|
590
|
+
tracker:
|
|
591
|
+
provider: jira-cloud
|
|
592
|
+
base-url: https://yourcompany.atlassian.net
|
|
593
|
+
candidate-query: assignee = currentUser() AND status = "To Do"
|
|
594
|
+
credentials:
|
|
595
|
+
email-env: TCW_JIRA_EMAIL
|
|
596
|
+
token-env: TCW_JIRA_API_TOKEN
|
|
597
|
+
transitions:
|
|
598
|
+
claim: Start Progress
|
|
599
|
+
timeout-seconds: 15 # optional
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
**Credentials are named, never stored.** The file holds the names of two
|
|
603
|
+
environment variables; TCW reads them at the moment it makes a request, so a token
|
|
604
|
+
cannot be committed by accident.
|
|
605
|
+
|
|
606
|
+
`tracker show` reports two different things, and the distinction matters:
|
|
607
|
+
|
|
608
|
+
- **claimable** — whether this ticket currently offers the transition you
|
|
609
|
+
configured as the claim.
|
|
610
|
+
- **exclusive** — whether your Jira workflow would actually refuse a second person
|
|
611
|
+
trying to take the same ticket.
|
|
612
|
+
|
|
613
|
+
Many Jira workflows allow a status change from any status, including the one it
|
|
614
|
+
leads to. On a workflow like that, two people who both take one ticket both
|
|
615
|
+
succeed and neither is told. So a ticket that has been started reports
|
|
616
|
+
`not exclusive` when that is the truth, and a ticket that has not been started
|
|
617
|
+
reports `not determined`, because it cannot show you what happens to the second
|
|
618
|
+
person. Making a workflow exclusive is a Jira administration change, not something
|
|
619
|
+
TCW can do for you.
|
|
620
|
+
|
|
621
|
+
**Taking a ticket.** `tracker import` moves the ticket through your configured
|
|
622
|
+
claim transition, assigns it to you if nobody had it, and then checks Jira again:
|
|
623
|
+
only when the ticket really is started and yours does it create a backlog item. The
|
|
624
|
+
ticket's text goes into the item as its raw input, with a link back, and the item's
|
|
625
|
+
request still gets written the usual way. A ticket assigned to someone else is
|
|
626
|
+
refused, and so is one that is already closed.
|
|
627
|
+
|
|
628
|
+
Running `import` again for the same ticket gives you the same item rather than a
|
|
629
|
+
second one, and if the first run took the ticket but stopped before creating the
|
|
630
|
+
item, the second run finishes the job. One ticket can deliberately become several
|
|
631
|
+
items with `--part api`, `--part web`, and so on. `unlink` removes a wrong binding
|
|
632
|
+
and keeps a record of it with your reason; it never changes the ticket in Jira.
|
|
633
|
+
|
|
634
|
+
Two limits to know. On a workflow that lets anyone start a ticket from any status,
|
|
635
|
+
two people can both take the same ticket, and TCW does not stop that. And two runs
|
|
636
|
+
by the same Jira account at the same moment can both create an item.
|
|
637
|
+
|
|
638
|
+
Two guarantees worth stating plainly. A project with no `tracker` block behaves
|
|
639
|
+
exactly as before, with no new required setting and no network access. And
|
|
640
|
+
`tcw validate` never contacts the tracker, which matters because projects commonly
|
|
641
|
+
run it when closing a work item — finishing your work must not depend on Jira being
|
|
642
|
+
reachable.
|
|
643
|
+
|
|
644
|
+
---
|
|
645
|
+
|
|
467
646
|
## Documentation
|
|
468
647
|
|
|
469
648
|
| Document | Covers |
|
|
@@ -483,21 +662,22 @@ Every command group also has `--help`, and a `check` that validates its tree.
|
|
|
483
662
|
|
|
484
663
|
## Skills — the judgment layer
|
|
485
664
|
|
|
486
|
-
The CLI is the _mechanism_.
|
|
487
|
-
_judgment_ that drives it — the parts a deterministic tool cannot decide.
|
|
665
|
+
The CLI is the _mechanism_. Fifteen skills in [`skills/`](skills/) supply the
|
|
666
|
+
_judgment_ that drives it — the parts a deterministic tool cannot decide. Nine
|
|
488
667
|
carry a distinct procedure; the other six all compose one lifecycle stage and
|
|
489
668
|
are listed together at the end.
|
|
490
669
|
|
|
491
|
-
| Skill | What it does
|
|
492
|
-
| ---------------------------------------------------------- |
|
|
493
|
-
| [`tcw-work`](skills/tcw-work/SKILL.md) | Plans a request through spec and plan, drives implementation and verification, triages the inbox, runs the lifecycle, decomposes epics |
|
|
494
|
-
| [`tcw-capabilities`](skills/tcw-capabilities/SKILL.md) | The capability-delta planning check, contradiction detection, and the ledger flip at completion
|
|
495
|
-
| [`tcw-taxonomy`](skills/tcw-taxonomy/SKILL.md) | Declaring vocabulary and features, linking them, and federating shared vocabulary
|
|
496
|
-
| [`tcw-plugin`](skills/tcw-plugin/SKILL.md) | Installs
|
|
497
|
-
| [`tcw-report`](skills/tcw-report/SKILL.md) | Reporting a `tcw` bug or suggestion upstream to [this project's issues](https://github.com/brocef/TCW/issues)
|
|
498
|
-
| [`tcw-triage-issues`](skills/tcw-triage-issues/SKILL.md) | Sweeps **your** project's GitHub issues and turns the ones worth doing into work items
|
|
499
|
-
| [`documentation-sync`](skills/documentation-sync/SKILL.md) | Keeps README, changelogs, release notes, and driving skills moving with the code that changes them
|
|
500
|
-
| [`tcw-post-mortem`](skills/tcw-post-mortem/SKILL.md) | Finds which lifecycle stage could first have caught a problem, once one has surfaced
|
|
670
|
+
| Skill | What it does |
|
|
671
|
+
| ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
672
|
+
| [`tcw-work`](skills/tcw-work/SKILL.md) | Plans a request through spec and plan, drives implementation and verification, triages the inbox, runs the lifecycle, decomposes epics, searches the board |
|
|
673
|
+
| [`tcw-capabilities`](skills/tcw-capabilities/SKILL.md) | The capability-delta planning check, contradiction detection, and the ledger flip at completion |
|
|
674
|
+
| [`tcw-taxonomy`](skills/tcw-taxonomy/SKILL.md) | Declaring vocabulary and features, linking them, and federating shared vocabulary |
|
|
675
|
+
| [`tcw-plugin`](skills/tcw-plugin/SKILL.md) | Installs the CLI from PyPI, and maps the other skills |
|
|
676
|
+
| [`tcw-report`](skills/tcw-report/SKILL.md) | Reporting a `tcw` bug or suggestion upstream to [this project's issues](https://github.com/brocef/TCW/issues) |
|
|
677
|
+
| [`tcw-triage-issues`](skills/tcw-triage-issues/SKILL.md) | Sweeps **your** project's GitHub issues and turns the ones worth doing into work items |
|
|
678
|
+
| [`documentation-sync`](skills/documentation-sync/SKILL.md) | Keeps README, changelogs, release notes, and driving skills moving with the code that changes them |
|
|
679
|
+
| [`tcw-post-mortem`](skills/tcw-post-mortem/SKILL.md) | Finds which lifecycle stage could first have caught a problem, once one has surfaced |
|
|
680
|
+
| [`autonomous-work`](skills/autonomous-work/SKILL.md) | Drives work items to completion unattended, consulting two read-only advisors wherever the lifecycle would ask you |
|
|
501
681
|
|
|
502
682
|
They name `tcw` commands and never reimplement tool logic: mechanism stays in the
|
|
503
683
|
binary, judgment stays in the skills.
|
|
@@ -515,13 +695,16 @@ The other five bake their stage in and ask only for the work item, which is
|
|
|
515
695
|
optional: `tcw-work-stage-request`, `tcw-work-stage-spec`,
|
|
516
696
|
`tcw-work-stage-plan`, `tcw-work-stage-implement`, `tcw-work-stage-verify`.
|
|
517
697
|
|
|
698
|
+
### Review agents and slash commands
|
|
699
|
+
|
|
518
700
|
Three read-only review agents ship alongside them — `tcw-verifier`,
|
|
519
701
|
`tcw-backlog-auditor`, and `tcw-post-mortem`, which accelerates the skill of the
|
|
520
702
|
same name — plus slash commands for each skill's main procedure
|
|
521
703
|
(`/tcw-plan-work`, `/tcw-drive-work-to-completion`, `/tcw-verify-work`,
|
|
522
|
-
`/tcw-process-inbox`, `/tcw-
|
|
523
|
-
`/tcw-
|
|
524
|
-
`/tcw-
|
|
704
|
+
`/tcw-process-inbox`, `/tcw-work-search`, `/tcw-triage-issues`,
|
|
705
|
+
`/tcw-audit-work-backlog`, `/tcw-consolidate-plans`, `/tcw-taxonomy-init`,
|
|
706
|
+
`/tcw-capabilities-init`, `/tcw-docs-sync-setup`, `/tcw-cut-version`,
|
|
707
|
+
`/tcw-post-mortem`).
|
|
525
708
|
|
|
526
709
|
---
|
|
527
710
|
|
|
@@ -13,6 +13,28 @@ They link by one-directional pointers — a capability names the taxonomy terms
|
|
|
13
13
|
involves, a work item names the capability it changes — and never copy each
|
|
14
14
|
other's content.
|
|
15
15
|
|
|
16
|
+
## Contents
|
|
17
|
+
|
|
18
|
+
- [The problem](#the-problem)
|
|
19
|
+
- [What it looks like](#what-it-looks-like)
|
|
20
|
+
- [Why many repositories is the case it is built for](#why-many-repositories-is-the-case-it-is-built-for)
|
|
21
|
+
- [What it deliberately refuses](#what-it-deliberately-refuses)
|
|
22
|
+
- [What adopting it costs](#what-adopting-it-costs)
|
|
23
|
+
- [Who it's for](#who-its-for)
|
|
24
|
+
- [Storage abstraction (the prime directive)](#storage-abstraction-the-prime-directive)
|
|
25
|
+
- [Install](#install)
|
|
26
|
+
- [As a plugin (recommended)](#as-a-plugin-recommended)
|
|
27
|
+
- [As a Python package](#as-a-python-package)
|
|
28
|
+
- [In a cloud environment](#in-a-cloud-environment)
|
|
29
|
+
- [Quickstart](#quickstart)
|
|
30
|
+
- [Working from your Jira tickets](#working-from-your-jira-tickets)
|
|
31
|
+
- [Documentation](#documentation)
|
|
32
|
+
- [Skills — the judgment layer](#skills--the-judgment-layer)
|
|
33
|
+
- [Reading a lifecycle stage](#reading-a-lifecycle-stage)
|
|
34
|
+
- [Review agents and slash commands](#review-agents-and-slash-commands)
|
|
35
|
+
- [Status](#status)
|
|
36
|
+
- [Further reading](#further-reading)
|
|
37
|
+
|
|
16
38
|
---
|
|
17
39
|
|
|
18
40
|
## The problem
|
|
@@ -191,8 +213,9 @@ Or, in the Claude **web app** or **desktop app**, open the plugin directory, add
|
|
|
191
213
|
by installing `tcw-cli` from PyPI with `pipx`, so one installed mid-session
|
|
192
214
|
cannot run until the next one begins. That first session needs network access. It
|
|
193
215
|
installs over an existing `pipx install tcw-cli` rather than beside it, and
|
|
194
|
-
leaves a development checkout (`pip install -e .`) alone.
|
|
195
|
-
|
|
216
|
+
leaves a development checkout (`pip install -e .`) alone. If `tcw` goes missing
|
|
217
|
+
anyway, `pipx install tcw-cli` is the whole fix — the **`tcw-plugin`** skill
|
|
218
|
+
carries the cases where it is not.
|
|
196
219
|
|
|
197
220
|
In **Codex** (skills only, no slash commands):
|
|
198
221
|
|
|
@@ -223,6 +246,89 @@ additionally requires **Node.js ≥ 22.12**; every other command is Python-only.
|
|
|
223
246
|
Released wheels carry the prebuilt web assets, so there is no frontend build step
|
|
224
247
|
and no network needed after install.
|
|
225
248
|
|
|
249
|
+
### In a cloud environment
|
|
250
|
+
|
|
251
|
+
A cloud agent session — Claude Code on the web, a Codex container, a CI job —
|
|
252
|
+
starts from a clean image and is thrown away when it ends, so a `tcw` you install
|
|
253
|
+
by hand is gone by the next one. Install it **from your repository**, with a
|
|
254
|
+
session-start hook, and every session gets it without anyone remembering to.
|
|
255
|
+
|
|
256
|
+
Add a script to your repository:
|
|
257
|
+
|
|
258
|
+
```sh
|
|
259
|
+
#!/usr/bin/env bash
|
|
260
|
+
# Make `tcw` available in a disposable agent container.
|
|
261
|
+
# Exit 0 on every path — a session must start even when this cannot finish.
|
|
262
|
+
set -u
|
|
263
|
+
|
|
264
|
+
command -v tcw >/dev/null 2>&1 && exit 0
|
|
265
|
+
|
|
266
|
+
# pipx where it exists; otherwise install into the container's own interpreter.
|
|
267
|
+
# That is the right answer *here* and nowhere else: the container is disposable
|
|
268
|
+
# and single-purpose, so there is no user environment to damage.
|
|
269
|
+
if command -v pipx >/dev/null 2>&1; then
|
|
270
|
+
pipx install tcw-cli >/dev/null 2>&1 || echo "tcw: pipx install tcw-cli failed"
|
|
271
|
+
elif ! python3 -m pip install tcw-cli >/dev/null 2>&1 &&
|
|
272
|
+
! python3 -m pip install tcw-cli --break-system-packages >/dev/null 2>&1; then
|
|
273
|
+
echo "tcw: pip install tcw-cli failed — the tcw CLI is not available."
|
|
274
|
+
fi
|
|
275
|
+
|
|
276
|
+
# An install that landed outside PATH is installed and unusable. $CLAUDE_ENV_FILE
|
|
277
|
+
# is the harness's own channel for repairing that.
|
|
278
|
+
if ! command -v tcw >/dev/null 2>&1 && [ -n "${CLAUDE_ENV_FILE:-}" ]; then
|
|
279
|
+
userbin="$(python3 -m site --user-base 2>/dev/null)/bin"
|
|
280
|
+
[ -x "$userbin/tcw" ] && echo "export PATH=\"$userbin:\$PATH\"" >>"$CLAUDE_ENV_FILE"
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
exit 0
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Then wire it to `SessionStart` in your repository's `.claude/settings.json`:
|
|
287
|
+
|
|
288
|
+
```json
|
|
289
|
+
{
|
|
290
|
+
"hooks": {
|
|
291
|
+
"SessionStart": [
|
|
292
|
+
{
|
|
293
|
+
"hooks": [
|
|
294
|
+
{
|
|
295
|
+
"type": "command",
|
|
296
|
+
"command": "\"${CLAUDE_PROJECT_DIR}\"/scripts/tcw_session_setup.sh"
|
|
297
|
+
}
|
|
298
|
+
]
|
|
299
|
+
}
|
|
300
|
+
]
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Three things make the difference between a hook that helps and one that wastes a
|
|
306
|
+
session:
|
|
307
|
+
|
|
308
|
+
- **Exit 0 on every path, and print only on failure.** A hook that fails the
|
|
309
|
+
session start over a missing CLI has cost more than the CLI was worth.
|
|
310
|
+
- **Print to stdout.** Claude Code adds a `SessionStart` hook's stdout to the
|
|
311
|
+
agent's context, where it will be read; stderr becomes a transcript notice
|
|
312
|
+
nobody sees.
|
|
313
|
+
- **Check for `tcw` first.** The hook runs every session, including the ones
|
|
314
|
+
where a previous install is still there.
|
|
315
|
+
|
|
316
|
+
**If your work store lives in another repository**, the container holds only the
|
|
317
|
+
repository it cloned, so the board is declared but absent. Run `tcw provision`
|
|
318
|
+
after the install — it obtains what the checkout does not have, and does nothing
|
|
319
|
+
on a machine that already holds it. See
|
|
320
|
+
[Working across repositories](docs/guide/multi-repo.md).
|
|
321
|
+
|
|
322
|
+
Installing the **plugin** in such a session is a separate step from installing the
|
|
323
|
+
CLI, and only needed where the harness does not carry your plugins in: append
|
|
324
|
+
`claude plugin marketplace add brocef/TCW` and `claude plugin install tcw@tcw` to
|
|
325
|
+
the same script, guarded on `command -v claude`.
|
|
326
|
+
|
|
327
|
+
This repository's own [`scripts/remote_session_setup.sh`](scripts/remote_session_setup.sh)
|
|
328
|
+
is the same pattern written for a _contributor_ rather than a user — it installs
|
|
329
|
+
the checkout with `pip install -e` instead of the release from PyPI, and installs
|
|
330
|
+
the plugin from the checkout too. Read it as the worked example.
|
|
331
|
+
|
|
226
332
|
## Quickstart
|
|
227
333
|
|
|
228
334
|
```sh
|
|
@@ -248,6 +354,79 @@ studies your code, proposes a first draft, refines it with you, and writes it.
|
|
|
248
354
|
|
|
249
355
|
---
|
|
250
356
|
|
|
357
|
+
## Working from your Jira tickets
|
|
358
|
+
|
|
359
|
+
A project can name the Jira Cloud site it uses, read its tickets, and take one as
|
|
360
|
+
a work item.
|
|
361
|
+
|
|
362
|
+
```sh
|
|
363
|
+
tcw work tracker list # tickets the configured query selects
|
|
364
|
+
tcw work tracker show ENG-482 # one ticket, and whether it is yours to take
|
|
365
|
+
tcw work tracker import ENG-482 # take the ticket and get a work item for it
|
|
366
|
+
tcw work tracker link <slug> ENG-482 # take it for an item you already have
|
|
367
|
+
tcw work tracker unlink <slug> --reason "wrong ticket"
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Configuration goes in the node's `tcw-config.yaml`:
|
|
371
|
+
|
|
372
|
+
```yaml
|
|
373
|
+
work:
|
|
374
|
+
tracker:
|
|
375
|
+
provider: jira-cloud
|
|
376
|
+
base-url: https://yourcompany.atlassian.net
|
|
377
|
+
candidate-query: assignee = currentUser() AND status = "To Do"
|
|
378
|
+
credentials:
|
|
379
|
+
email-env: TCW_JIRA_EMAIL
|
|
380
|
+
token-env: TCW_JIRA_API_TOKEN
|
|
381
|
+
transitions:
|
|
382
|
+
claim: Start Progress
|
|
383
|
+
timeout-seconds: 15 # optional
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
**Credentials are named, never stored.** The file holds the names of two
|
|
387
|
+
environment variables; TCW reads them at the moment it makes a request, so a token
|
|
388
|
+
cannot be committed by accident.
|
|
389
|
+
|
|
390
|
+
`tracker show` reports two different things, and the distinction matters:
|
|
391
|
+
|
|
392
|
+
- **claimable** — whether this ticket currently offers the transition you
|
|
393
|
+
configured as the claim.
|
|
394
|
+
- **exclusive** — whether your Jira workflow would actually refuse a second person
|
|
395
|
+
trying to take the same ticket.
|
|
396
|
+
|
|
397
|
+
Many Jira workflows allow a status change from any status, including the one it
|
|
398
|
+
leads to. On a workflow like that, two people who both take one ticket both
|
|
399
|
+
succeed and neither is told. So a ticket that has been started reports
|
|
400
|
+
`not exclusive` when that is the truth, and a ticket that has not been started
|
|
401
|
+
reports `not determined`, because it cannot show you what happens to the second
|
|
402
|
+
person. Making a workflow exclusive is a Jira administration change, not something
|
|
403
|
+
TCW can do for you.
|
|
404
|
+
|
|
405
|
+
**Taking a ticket.** `tracker import` moves the ticket through your configured
|
|
406
|
+
claim transition, assigns it to you if nobody had it, and then checks Jira again:
|
|
407
|
+
only when the ticket really is started and yours does it create a backlog item. The
|
|
408
|
+
ticket's text goes into the item as its raw input, with a link back, and the item's
|
|
409
|
+
request still gets written the usual way. A ticket assigned to someone else is
|
|
410
|
+
refused, and so is one that is already closed.
|
|
411
|
+
|
|
412
|
+
Running `import` again for the same ticket gives you the same item rather than a
|
|
413
|
+
second one, and if the first run took the ticket but stopped before creating the
|
|
414
|
+
item, the second run finishes the job. One ticket can deliberately become several
|
|
415
|
+
items with `--part api`, `--part web`, and so on. `unlink` removes a wrong binding
|
|
416
|
+
and keeps a record of it with your reason; it never changes the ticket in Jira.
|
|
417
|
+
|
|
418
|
+
Two limits to know. On a workflow that lets anyone start a ticket from any status,
|
|
419
|
+
two people can both take the same ticket, and TCW does not stop that. And two runs
|
|
420
|
+
by the same Jira account at the same moment can both create an item.
|
|
421
|
+
|
|
422
|
+
Two guarantees worth stating plainly. A project with no `tracker` block behaves
|
|
423
|
+
exactly as before, with no new required setting and no network access. And
|
|
424
|
+
`tcw validate` never contacts the tracker, which matters because projects commonly
|
|
425
|
+
run it when closing a work item — finishing your work must not depend on Jira being
|
|
426
|
+
reachable.
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
251
430
|
## Documentation
|
|
252
431
|
|
|
253
432
|
| Document | Covers |
|
|
@@ -267,21 +446,22 @@ Every command group also has `--help`, and a `check` that validates its tree.
|
|
|
267
446
|
|
|
268
447
|
## Skills — the judgment layer
|
|
269
448
|
|
|
270
|
-
The CLI is the _mechanism_.
|
|
271
|
-
_judgment_ that drives it — the parts a deterministic tool cannot decide.
|
|
449
|
+
The CLI is the _mechanism_. Fifteen skills in [`skills/`](skills/) supply the
|
|
450
|
+
_judgment_ that drives it — the parts a deterministic tool cannot decide. Nine
|
|
272
451
|
carry a distinct procedure; the other six all compose one lifecycle stage and
|
|
273
452
|
are listed together at the end.
|
|
274
453
|
|
|
275
|
-
| Skill | What it does
|
|
276
|
-
| ---------------------------------------------------------- |
|
|
277
|
-
| [`tcw-work`](skills/tcw-work/SKILL.md) | Plans a request through spec and plan, drives implementation and verification, triages the inbox, runs the lifecycle, decomposes epics |
|
|
278
|
-
| [`tcw-capabilities`](skills/tcw-capabilities/SKILL.md) | The capability-delta planning check, contradiction detection, and the ledger flip at completion
|
|
279
|
-
| [`tcw-taxonomy`](skills/tcw-taxonomy/SKILL.md) | Declaring vocabulary and features, linking them, and federating shared vocabulary
|
|
280
|
-
| [`tcw-plugin`](skills/tcw-plugin/SKILL.md) | Installs
|
|
281
|
-
| [`tcw-report`](skills/tcw-report/SKILL.md) | Reporting a `tcw` bug or suggestion upstream to [this project's issues](https://github.com/brocef/TCW/issues)
|
|
282
|
-
| [`tcw-triage-issues`](skills/tcw-triage-issues/SKILL.md) | Sweeps **your** project's GitHub issues and turns the ones worth doing into work items
|
|
283
|
-
| [`documentation-sync`](skills/documentation-sync/SKILL.md) | Keeps README, changelogs, release notes, and driving skills moving with the code that changes them
|
|
284
|
-
| [`tcw-post-mortem`](skills/tcw-post-mortem/SKILL.md) | Finds which lifecycle stage could first have caught a problem, once one has surfaced
|
|
454
|
+
| Skill | What it does |
|
|
455
|
+
| ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
456
|
+
| [`tcw-work`](skills/tcw-work/SKILL.md) | Plans a request through spec and plan, drives implementation and verification, triages the inbox, runs the lifecycle, decomposes epics, searches the board |
|
|
457
|
+
| [`tcw-capabilities`](skills/tcw-capabilities/SKILL.md) | The capability-delta planning check, contradiction detection, and the ledger flip at completion |
|
|
458
|
+
| [`tcw-taxonomy`](skills/tcw-taxonomy/SKILL.md) | Declaring vocabulary and features, linking them, and federating shared vocabulary |
|
|
459
|
+
| [`tcw-plugin`](skills/tcw-plugin/SKILL.md) | Installs the CLI from PyPI, and maps the other skills |
|
|
460
|
+
| [`tcw-report`](skills/tcw-report/SKILL.md) | Reporting a `tcw` bug or suggestion upstream to [this project's issues](https://github.com/brocef/TCW/issues) |
|
|
461
|
+
| [`tcw-triage-issues`](skills/tcw-triage-issues/SKILL.md) | Sweeps **your** project's GitHub issues and turns the ones worth doing into work items |
|
|
462
|
+
| [`documentation-sync`](skills/documentation-sync/SKILL.md) | Keeps README, changelogs, release notes, and driving skills moving with the code that changes them |
|
|
463
|
+
| [`tcw-post-mortem`](skills/tcw-post-mortem/SKILL.md) | Finds which lifecycle stage could first have caught a problem, once one has surfaced |
|
|
464
|
+
| [`autonomous-work`](skills/autonomous-work/SKILL.md) | Drives work items to completion unattended, consulting two read-only advisors wherever the lifecycle would ask you |
|
|
285
465
|
|
|
286
466
|
They name `tcw` commands and never reimplement tool logic: mechanism stays in the
|
|
287
467
|
binary, judgment stays in the skills.
|
|
@@ -299,13 +479,16 @@ The other five bake their stage in and ask only for the work item, which is
|
|
|
299
479
|
optional: `tcw-work-stage-request`, `tcw-work-stage-spec`,
|
|
300
480
|
`tcw-work-stage-plan`, `tcw-work-stage-implement`, `tcw-work-stage-verify`.
|
|
301
481
|
|
|
482
|
+
### Review agents and slash commands
|
|
483
|
+
|
|
302
484
|
Three read-only review agents ship alongside them — `tcw-verifier`,
|
|
303
485
|
`tcw-backlog-auditor`, and `tcw-post-mortem`, which accelerates the skill of the
|
|
304
486
|
same name — plus slash commands for each skill's main procedure
|
|
305
487
|
(`/tcw-plan-work`, `/tcw-drive-work-to-completion`, `/tcw-verify-work`,
|
|
306
|
-
`/tcw-process-inbox`, `/tcw-
|
|
307
|
-
`/tcw-
|
|
308
|
-
`/tcw-
|
|
488
|
+
`/tcw-process-inbox`, `/tcw-work-search`, `/tcw-triage-issues`,
|
|
489
|
+
`/tcw-audit-work-backlog`, `/tcw-consolidate-plans`, `/tcw-taxonomy-init`,
|
|
490
|
+
`/tcw-capabilities-init`, `/tcw-docs-sync-setup`, `/tcw-cut-version`,
|
|
491
|
+
`/tcw-post-mortem`).
|
|
309
492
|
|
|
310
493
|
---
|
|
311
494
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tcw-cli"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.1.2"
|
|
8
8
|
description = "Taxonomy · Capabilities · Work — a storage-abstracted framework for describing and evolving a software project."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -35,4 +35,11 @@ include = ["tcw*"]
|
|
|
35
35
|
|
|
36
36
|
[tool.pytest.ini_options]
|
|
37
37
|
testpaths = ["tests"]
|
|
38
|
+
# The repository root on sys.path, so `from evals import ...` resolves. The
|
|
39
|
+
# eval-harness tests import it, and `evals` is deliberately not a published
|
|
40
|
+
# package (`packages.find` includes only `tcw*`), so the editable install does
|
|
41
|
+
# not put it there. `python -m pytest` happened to work anyway — that form puts
|
|
42
|
+
# the current directory on sys.path and bare `pytest` does not — which is why
|
|
43
|
+
# CI, which runs bare `pytest`, was the only place this failed.
|
|
44
|
+
pythonpath = ["."]
|
|
38
45
|
norecursedirs = [".venv", "build", "dist", "*.egg-info"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.1.2"
|
|
@@ -9,7 +9,8 @@ from tcw.store.base import AmbiguousRef
|
|
|
9
9
|
from tcw.store.fs import FsCapabilitiesStore, find_node, git_root
|
|
10
10
|
|
|
11
11
|
NAME = "capabilities"
|
|
12
|
-
SUBCOMMANDS = {"init", "list", "show", "path", "add", "search", "check", "set", "reset", "
|
|
12
|
+
SUBCOMMANDS = {"init", "list", "show", "path", "add", "search", "check", "set", "reset", "rm",
|
|
13
|
+
"extends", "drift"}
|
|
13
14
|
DEFAULT_SUBCOMMAND = "show" # `tcw capabilities <path>` == `tcw capabilities show <path>`
|
|
14
15
|
|
|
15
16
|
|
|
@@ -129,6 +130,19 @@ def _reset(args: argparse.Namespace) -> int:
|
|
|
129
130
|
return 0
|
|
130
131
|
|
|
131
132
|
|
|
133
|
+
def _rm(args: argparse.Namespace) -> int:
|
|
134
|
+
st = _store()
|
|
135
|
+
if st is None:
|
|
136
|
+
return 1
|
|
137
|
+
try:
|
|
138
|
+
st.remove(args.id)
|
|
139
|
+
except (ValueError, RefError) as e: # AmbiguousRef carries its own message
|
|
140
|
+
print(f"tcw capabilities rm: {e}", file=sys.stderr)
|
|
141
|
+
return 1
|
|
142
|
+
print(f"Removed capability {args.id}")
|
|
143
|
+
return 0
|
|
144
|
+
|
|
145
|
+
|
|
132
146
|
def _search(args: argparse.Namespace) -> int:
|
|
133
147
|
st = _store()
|
|
134
148
|
if st is None:
|
|
@@ -294,6 +308,10 @@ def add_subparser(sub: argparse._SubParsersAction) -> None:
|
|
|
294
308
|
prst.add_argument("id", metavar="path")
|
|
295
309
|
prst.set_defaults(func=_reset)
|
|
296
310
|
|
|
311
|
+
prm = g.add_parser("rm", help="remove a local capability")
|
|
312
|
+
prm.add_argument("id", metavar="path")
|
|
313
|
+
prm.set_defaults(func=_rm)
|
|
314
|
+
|
|
297
315
|
pse = g.add_parser("search", help="search names + bodies")
|
|
298
316
|
pse.add_argument("query")
|
|
299
317
|
pse.set_defaults(func=_search)
|
|
@@ -535,6 +535,15 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
535
535
|
except ValueError as error:
|
|
536
536
|
print(f"tcw: {error}", file=sys.stderr)
|
|
537
537
|
return 1
|
|
538
|
+
except yaml.YAMLError as error:
|
|
539
|
+
# A malformed YAML file is the user's, not a bug in TCW, so it reads as
|
|
540
|
+
# a message rather than a traceback. Here rather than at each of the
|
|
541
|
+
# twenty-odd `load_yaml` calls that do not catch it: refusing is already
|
|
542
|
+
# the right answer at every one of them — `init` must not overwrite a
|
|
543
|
+
# config it cannot read — and only the presentation was wrong. The
|
|
544
|
+
# loader's message names the file.
|
|
545
|
+
print(f"tcw: {error}", file=sys.stderr)
|
|
546
|
+
return 1
|
|
538
547
|
except subprocess.CalledProcessError as error:
|
|
539
548
|
# Deliberately generic: the only policy here is "a git subprocess
|
|
540
549
|
# failed", which is true of every component. git's own diagnostic has
|