workstate-bootstrap 0.5.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.
Files changed (30) hide show
  1. workstate_bootstrap-0.5.2/.gitignore +8 -0
  2. workstate_bootstrap-0.5.2/CHANGELOG.md +240 -0
  3. workstate_bootstrap-0.5.2/PKG-INFO +179 -0
  4. workstate_bootstrap-0.5.2/README.md +160 -0
  5. workstate_bootstrap-0.5.2/pyproject.toml +36 -0
  6. workstate_bootstrap-0.5.2/src/workstate_bootstrap/__init__.py +6 -0
  7. workstate_bootstrap-0.5.2/src/workstate_bootstrap/__main__.py +5 -0
  8. workstate_bootstrap-0.5.2/src/workstate_bootstrap/cli.py +610 -0
  9. workstate_bootstrap-0.5.2/src/workstate_bootstrap/install.py +2057 -0
  10. workstate_bootstrap-0.5.2/src/workstate_bootstrap/mcp_sync.py +293 -0
  11. workstate_bootstrap-0.5.2/src/workstate_bootstrap/subcommands.py +1358 -0
  12. workstate_bootstrap-0.5.2/tests/__init__.py +5 -0
  13. workstate_bootstrap-0.5.2/tests/test_bootstrap_install_rehearsal.py +479 -0
  14. workstate_bootstrap-0.5.2/tests/test_cli_profile.py +200 -0
  15. workstate_bootstrap-0.5.2/tests/test_doctor_repair_sync.py +235 -0
  16. workstate_bootstrap-0.5.2/tests/test_ensure_hooks_path_make.py +98 -0
  17. workstate_bootstrap-0.5.2/tests/test_install.py +2499 -0
  18. workstate_bootstrap-0.5.2/tests/test_install_manifest_walker.py +780 -0
  19. workstate_bootstrap-0.5.2/tests/test_install_profile_all_lifecycle.py +147 -0
  20. workstate_bootstrap-0.5.2/tests/test_install_profiles.py +275 -0
  21. workstate_bootstrap-0.5.2/tests/test_manifest_build.py +89 -0
  22. workstate_bootstrap-0.5.2/tests/test_mcp_sync_cli.py +258 -0
  23. workstate_bootstrap-0.5.2/tests/test_mcp_sync_e2e.py +212 -0
  24. workstate_bootstrap-0.5.2/tests/test_mcp_sync_malformed.py +185 -0
  25. workstate_bootstrap-0.5.2/tests/test_mcp_sync_prune.py +210 -0
  26. workstate_bootstrap-0.5.2/tests/test_mcp_sync_unit.py +181 -0
  27. workstate_bootstrap-0.5.2/tests/test_package_metadata.py +51 -0
  28. workstate_bootstrap-0.5.2/tests/test_render_seam.py +130 -0
  29. workstate_bootstrap-0.5.2/tests/test_root_visible_task_plans.py +164 -0
  30. workstate_bootstrap-0.5.2/tests/test_subcommands.py +1765 -0
@@ -0,0 +1,8 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .pytest_cache/
5
+ .venv/
6
+ venv/
7
+ build/
8
+ dist/
@@ -0,0 +1,240 @@
1
+ # Changelog — workstate-bootstrap
2
+
3
+ ## Unreleased
4
+
5
+ ## [0.5.2] — 2026-05-20
6
+
7
+ ### Changed
8
+
9
+ - **Bump the default managed handoff server pin** to
10
+ `mcp-workstate-handoff@0.11.5` so fresh `workstate-bootstrap install`
11
+ dogfood installs pick up the `ACTIVE TASK PLANS` task-plan-path fix by
12
+ default. `mcp-workstate-orchestrator` remains pinned at `0.4.7`.
13
+
14
+ ## [0.5.1] — 2026-05-11
15
+
16
+ ### Fixed
17
+
18
+ - **WORKSTATE-REF-57 — stale shared-surface symlinks now repointed on rerun.**
19
+ When a consumer was installed pre-v0.2.0 (legacy root layout
20
+ `<clone>/<surface>`) and the layout subsequently moved into
21
+ `<clone>/packages/workstate-system/<surface>`, the target-side
22
+ `scripts/hooks -> ../.agentic/remote/scripts/hooks` symlink survived
23
+ every subsequent `workstate-bootstrap install` because the pre-fix
24
+ `points_into_clone` check still passed lexically for the broken
25
+ resolved path. `_materialize_surfaces` now classifies each existing
26
+ symlink into three buckets — resolves-to-expected (shared,
27
+ idempotent), lexically inside our remote subtree but stale-or-broken
28
+ (repointed to the canonical target, audited to stdout as
29
+ `repointed: <surface>`), and foreign (preserved as local override).
30
+ The lexical containment check uses `os.readlink` +
31
+ `os.path.normpath` so broken targets are classified without raising
32
+ during `Path.resolve(strict=True)`.
33
+
34
+ ## [0.5.0] — 2026-05-10
35
+
36
+ ### Changed
37
+
38
+ - **WORKSTATE-REF-56 — cross-harness install manifest is now the single source of
39
+ truth for hook adapter wiring.** `config/agent-workflows/portable_commands.json`
40
+ schema v2 introduces a top-level `hooks[]` array; install dispatches
41
+ adapter rows through a manifest-driven walker (closed-set operation
42
+ table) instead of bespoke per-harness writers. New harnesses (Codex,
43
+ VS Code, …) are onboarded by appending adapter rows.
44
+ - **CLI default profile flips back to `all`** so a no-argument
45
+ `workstate-bootstrap install` materializes the full surface set out of
46
+ the box — per-agent generated surfaces (`.claude/skills`,
47
+ `.claude/commands`, `.github/prompts`, `.codex/skills`), shared
48
+ overlay symlinks (`scripts/hooks`, `Makefile.d`, `scripts/workstate`,
49
+ …), and the lifecycle hoist (`Makefile.d/lifecycle.mk` plus the
50
+ sentinel-bracketed `-include` block). `--profile minimal` and
51
+ `--profile lifecycle` remain opt-in for lean installs. The library
52
+ `install()` API has always defaulted to `"all"`; this realigns the
53
+ two layers.
54
+ - **The install manifest (`.workstate-bootstrap.json`) now records the
55
+ active profile** under `manifest["profile"]` so downstream tools
56
+ (`sync`, `doctor`, rehearsals) can reason about what the consumer
57
+ installed without re-inferring it from the surface set.
58
+ - **Stop-hook wiring is fully opt-in across every harness shipped by
59
+ the manifest.** The legacy `--harness-hook-scope` flag is replaced by
60
+ four boolean flags: `--install-claude-stop-hook` (shared, checked-in
61
+ `.claude/settings.json`), `--install-claude-stop-hook-local`
62
+ (user-owned, gitignored `.claude/settings.local.json`),
63
+ `--install-codex-stop-hook` (`.codex/hooks/stop.json`), and
64
+ `--install-vscode-stop-hook` (`.vscode/agentic-stop-hooks.json`).
65
+ All four default off — no file is touched unless the operator
66
+ explicitly opts in. The library `install()` API surfaces the same
67
+ switches as `install_claude_stop_hook` / `install_claude_stop_hook_local`
68
+ / `install_codex_stop_hook` / `install_vscode_stop_hook`.
69
+
70
+ ## [0.4.2] — 2026-05-10
71
+
72
+ ### Changed
73
+
74
+ - **Bump default managed MCP server pins** to `mcp-workstate-handoff@0.11.1`
75
+ and `mcp-workstate-orchestrator@0.4.5` so consumer repos pick up the
76
+ WORKSTATE-REF-54 (multi-active CURRENT_TASK projection, import/export
77
+ malformed-payload rejection, target_branch/worktree_path/plan_path
78
+ preservation) and WORKSTATE-REF-55 (compaction env-var namespace
79
+ consolidation under `AGENT_HANDOFF_COMPACTION_*` with `WORKSTATE_*` kept
80
+ as a deprecated alias) fixes by default.
81
+
82
+ ## [0.4.1] — 2026-05-09
83
+
84
+ ### Fixed
85
+
86
+ - **`--profile all` now performs the lifecycle hoist** (WORKSTATE-REF-48). The
87
+ legacy default profile shipped lifecycle-referencing skills
88
+ (`branch-lifecycle`, `tdd`, `incremental-implementation`,
89
+ `branch-review`, `handoff-lifecycle`) but did not install the
90
+ matching `Makefile.d/lifecycle.mk` and
91
+ `scripts/workstate/lifecycle/` runner that those skills' `make
92
+ task-start` / `make slice-start` / `make context` /
93
+ `make review-ready` / `make handoff-close-check` /
94
+ `make format-all` references resolve through. Consumer repos
95
+ bootstrapped under `--profile all` now receive the runner and the
96
+ sentinel-bracketed `-include Makefile.d/*.mk` directive, so the
97
+ skill manifest and the make graph stay aligned.
98
+
99
+ ### Changed
100
+
101
+ - **Default managed MCP servers are now version-pinned.** The built-in
102
+ `--mcp-servers default` map writes `uvx mcp-workstate-handoff@0.11.0` and
103
+ `uvx mcp-workstate-orchestrator@0.4.4` (rather than unpinned `uvx
104
+ mcp-workstate-handoff` / `uvx mcp-workstate-orchestrator`) so consumer repos
105
+ do not silently drift when PyPI advances independently of the overlay
106
+ tag they bootstrapped against. Operators wanting a different pin
107
+ continue to pass `--mcp-servers <path>`.
108
+ - **Raise `workstate-protocol` lower bound to `>=0.1.4,<0.2.0`** to match
109
+ the floor pinned by `mcp-workstate-handoff` 0.11.0 and
110
+ `mcp-workstate-orchestrator` 0.4.4 — the two packages bootstrap launches
111
+ via `uvx` — so the bootstrap venv cannot resolve a protocol release
112
+ older than what those servers import at startup.
113
+
114
+ ## [0.4.0] — 2026-05-04
115
+
116
+ ### Added
117
+
118
+ - **Install profile contract: `--profile {minimal,lifecycle,all}`**
119
+ (implementation note / WORKSTATE-REF-40 implementation note.5.a). The CLI now accepts an explicit
120
+ install profile flag and honors it across the manifest layers, so
121
+ consumer repos can pick a smaller hoist surface than the default.
122
+ - **Hoist `Makefile.d/plans.mk` + `git-plan-cat.sh` stub** (implementation note /
123
+ WORKSTATE-REF-38 implementation note). Consumer repos installed via `workstate-bootstrap`
124
+ pick up `make plan-show / plan-edit / plans-list / plan-register`
125
+ out of the box; the targets shell out to `uvx mcp-workstate-handoff`
126
+ under the hood.
127
+
128
+ ### Changed
129
+
130
+ - Bootstrap installs and rehearsals are validated against
131
+ `mcp-workstate-handoff>=0.8.0` (the version that ships the
132
+ `plan_resolve` / `plan_cli` surface targeted by the new make
133
+ recipes).
134
+
135
+ ## [0.3.1] — 2026-05-03
136
+
137
+ - **implementation note BR-01 — raise `workstate-protocol` lower bound to
138
+ `>=0.1.2,<0.2.0`.** Bootstrap's default install path invokes
139
+ `uvx mcp-workstate-handoff`, which imports `workstate_protocol.branch_naming`
140
+ at startup; the previous `>=0.1.0` floor let `uvx` resolve a protocol
141
+ release missing the module, crashing init-state on a fresh install. A
142
+ new packaging test (`tests/test_package_metadata.py`) pins the floor
143
+ so the declaration cannot silently drift back below the contract.
144
+ - **implementation note implementation note — install rehearsal pins six-hook surface +
145
+ helper materialization.** `SHARED_GIT_HOOK_NAMES` now includes
146
+ `pre-commit` (in addition to `post-checkout`, `post-commit`,
147
+ `post-merge`, `post-rewrite`, `pre-push`); the install rehearsal
148
+ test asserts that `core.hooksPath` resolves to the directory
149
+ carrying all six executable hook scripts AND that the Python helper
150
+ `scripts/hooks/check_branch_naming.py` (the delegate the
151
+ post-checkout / pre-commit / pre-push hooks `exec`) is materialized
152
+ alongside them. Without the helper, every branch-naming gate
153
+ silently no-ops. The shared surface itself is unchanged
154
+ (`scripts/hooks` is symlinked from `.agentic/remote`); the new
155
+ assertion catches a future regression where the upstream package
156
+ drops the helper.
157
+ - **Manifest renamed: `.workstate-overlay.json` → `.workstate-bootstrap.json`
158
+ (schema_version bumped to 2).** Resolves a name collision with consumer
159
+ repos that also use `.workstate-overlay.json` for unrelated config. On first
160
+ run, an existing `.workstate-overlay.json` carrying the bootstrap shape
161
+ (top-level dict with a list `surfaces` key) is renamed in-place via
162
+ `git mv` (or filesystem rename when the target is not a git worktree).
163
+ Consumer-owned files at the legacy name are left untouched. The Python
164
+ alias `OVERLAY_MANIFEST_NAME` is preserved (now pointing at the canonical
165
+ filename) for downstream import compatibility.
166
+ - **Managed MCP defaults now launch stdio servers.** The built-in
167
+ `--mcp-servers default` map writes `uvx mcp-workstate-handoff
168
+ --workspace-root . serve-stdio` and `uvx mcp-workstate-orchestrator
169
+ --workspace-root . serve-stdio` into `.mcp.json`,
170
+ `.vscode/mcp.json`, and `.codex/config.toml`, so external clients
171
+ start runnable MCP servers from a fresh install or update.
172
+ - **`regenerate-task-views` harness hook contract dropped (implementation note).**
173
+ Bootstrap no longer materializes any Claude / VS Code / Codex hook
174
+ wiring that invokes `regenerate-task-views`; `DASHBOARD.txt` is now
175
+ auto-regenerated server-side inside `mcp-workstate-handoff` on every
176
+ state-mutating MCP call. The shared `scripts/hooks/` surface is still
177
+ materialized; `regenerate-task-views.sh` remains there only as a
178
+ documented manual fallback for the auto-regen opt-out path
179
+ (`WORKSTATE_HANDOFF_DASHBOARD_AUTO_REGEN=0`). Operators upgrading from
180
+ 0.3.0 do not need to touch any harness config — the next
181
+ `workstate-bootstrap update` removes the obsolete hook wiring.
182
+
183
+ ## 0.3.0 — 2026-04-28
184
+
185
+ - **Install-time state provisioning (implementation note).** `install` now runs
186
+ the handoff server's `init-state` after surface/config materialization
187
+ but before `core.hooksPath` is set, so a fresh install ends with a
188
+ schema-current `.task-state/handoff.db` and `.task-state/exports/`
189
+ ready for the first MCP call. The init-state invocation is resolved
190
+ from the same `mcp_servers` map written into `.mcp.json` /
191
+ `.vscode/mcp.json` / `.codex/config.toml` (avoiding dogfood version
192
+ skew between PyPI and local-source schemas), and the bootstrap
193
+ manifest's `remote_url` is threaded through `--expected-remote-url`
194
+ so a stale adjacent overlay from a different remote is rejected.
195
+ Skipped under `--no-mcp-servers`.
196
+ - **Required-surfaces refusal runs before the generator and
197
+ init-state.** A failing required-surface check now leaves no
198
+ `.task-state/`, no generated artifacts, and no manifest behind on
199
+ disk, so refused installs no longer half-write the target.
200
+ - **`status` reports handoff state.** When the install registered MCP
201
+ servers, `status` invokes `init-state --check` and appends the
202
+ resolved `state_dir` / `db_path` / `exports_dir` / `schema_version` /
203
+ `initialized` to the summary. `--no-mcp-servers` installs suppress
204
+ the section.
205
+ - **`doctor` flags missing `.task-state/handoff.db` as `state_drift`,**
206
+ gated on `.mcp.json` being present in the manifest's `configs` array
207
+ so config-only installs (`--no-mcp-servers`) do not produce
208
+ false-positive drift.
209
+ - **`switch_task` cold-start fix.** implementation note implementation note (in
210
+ `mcp-workstate-handoff` 0.5.0+) drops `BranchMismatchError` from
211
+ `switch_task`; the cold-start cycle (register task → `switch_task`
212
+ → first content write) now completes from any branch. Branch
213
+ enforcement on content writes (`record_event`, `close_slice`,
214
+ `set_handoff_state`, `record_review_finding`,
215
+ `record_verified_test`) is unchanged — bootstrap's docs reflect
216
+ this, but the behavior change lives in the handoff package.
217
+
218
+ ## 0.2.1 — 2026-04-26
219
+
220
+ - Add `pyyaml>=6` to runtime dependencies. The agent-workflow generator
221
+ imports `yaml` to read `skill.yaml`; bootstrap invokes the generator
222
+ via its own `sys.executable`, so PyYAML must be present in bootstrap's
223
+ uvx-isolated venv. Without it, install fails with
224
+ `PyYAML is required to read skill.yaml` on a clean uvx run.
225
+
226
+ ## 0.2.0 — 2026-04-26
227
+
228
+ - Resolve shared overlay surfaces and the agent-workflow generator under
229
+ `packages/workstate-system/` (the workstate monorepo layout) with
230
+ fallback to the clone root for legacy hoisted overlays. Fixes
231
+ `BootstrapManifestValidationError: required surface 'scripts/hooks' was
232
+ not materialized` against monorepo refs at or after implementation note step 1.
233
+ - Rehearsal fixture (`fake_remote_with_generator`) now mirrors the real
234
+ monorepo layout so this regression cannot return silently.
235
+
236
+ ### Note on previously published refs
237
+
238
+ The monorepo `v0.1.0` tag pre-dates this fix. Consumers using
239
+ `uvx --from "...@v0.1.0..." workstate-bootstrap install ...` will hit the
240
+ required-surface error. Pin to `v0.1.1` or later.
@@ -0,0 +1,179 @@
1
+ Metadata-Version: 2.4
2
+ Name: workstate-bootstrap
3
+ Version: 0.5.2
4
+ Summary: Bootstrap CLI that hoists the shared workstate-system surface into consumer repos.
5
+ Project-URL: Homepage, https://github.com/darce/workstate
6
+ Project-URL: Source, https://github.com/darce/workstate/tree/main/packages/workstate-bootstrap
7
+ Project-URL: Documentation, https://github.com/darce/workstate/blob/main/docs/CONSUMER.md
8
+ Project-URL: Issues, https://github.com/darce/workstate/issues
9
+ Author: darce
10
+ License: Proprietary
11
+ Requires-Python: >=3.11
12
+ Requires-Dist: pyyaml>=6
13
+ Requires-Dist: tomlkit>=0.13
14
+ Requires-Dist: workstate-protocol<0.2.0,>=0.1.4
15
+ Provides-Extra: dev
16
+ Requires-Dist: mcp-workstate-handoff; (python_version >= '3.12') and extra == 'dev'
17
+ Requires-Dist: pytest>=8; extra == 'dev'
18
+ Description-Content-Type: text/markdown
19
+
20
+ # workstate-bootstrap
21
+
22
+ Pip-installable CLI that hoists the shared workstate-system surface
23
+ (typed protocol, two MCP servers, hooks, skills, generated agent
24
+ workflows) into consumer repositories. Lives inside
25
+ [`darce/workstate`](https://github.com/darce/workstate).
26
+
27
+ Consumers run `workstate-bootstrap install --target <path>` once; it
28
+ clones the monorepo, materializes the overlay, and registers both
29
+ managed MCP servers (`mcp-workstate-handoff`, `mcp-workstate-orchestrator`)
30
+ across `.mcp.json`, `.vscode/mcp.json`, and `.codex/config.toml`. No
31
+ hand-edits required.
32
+
33
+ ## Install
34
+
35
+ ### From PyPI (recommended)
36
+
37
+ ```bash
38
+ uvx --from workstate-bootstrap workstate-bootstrap install --target /path/to/your/repo
39
+ # or, persistent:
40
+ uv tool install workstate-bootstrap
41
+ ```
42
+
43
+ ### From the monorepo source tree (development)
44
+
45
+ ```bash
46
+ cd packages/workstate-bootstrap
47
+ python -m pip install -e ".[dev]"
48
+ ```
49
+
50
+ ### Direct from git (private-repo phase, before PyPI release)
51
+
52
+ One-shot (no install — fetches each invocation):
53
+
54
+ ```bash
55
+ uvx --from "git+https://github.com/darce/workstate@workstate-bootstrap-v0.2.1#subdirectory=packages/workstate-bootstrap" \
56
+ workstate-bootstrap install \
57
+ --target /path/to/your/repo
58
+ ```
59
+
60
+ Persistent (recommended once you start running `status` / `doctor`
61
+ regularly — installs `workstate-bootstrap` onto `$PATH`):
62
+
63
+ ```bash
64
+ uv tool install "git+https://github.com/darce/workstate@workstate-bootstrap-v0.2.1#subdirectory=packages/workstate-bootstrap"
65
+ # then:
66
+ workstate-bootstrap status --target /path/to/your/repo
67
+ workstate-bootstrap doctor --target /path/to/your/repo
68
+ # upgrade later:
69
+ uv tool upgrade workstate-bootstrap
70
+ ```
71
+
72
+ > **Hardlink warning on first install?** If you see
73
+ > `Failed to hardlink files; falling back to full copy`, your `uv`
74
+ > cache and tool dir live on different filesystems. The install still
75
+ > succeeds; silence the warning with `export UV_LINK_MODE=copy` in
76
+ > your shell profile.
77
+
78
+ ## Subcommands
79
+
80
+ ```text
81
+ workstate-bootstrap install --target <path> [--remote-ref <tag>] [--mcp-servers <default|path>] [--no-mcp-servers]
82
+ workstate-bootstrap update --target <path> --remote-ref <tag>
83
+ workstate-bootstrap status --target <path>
84
+ workstate-bootstrap doctor --target <path> [--mcp-servers <default|path>]
85
+ workstate-bootstrap repair --target <path> [--force-dirty] [--mcp-servers <default|path>]
86
+ ```
87
+
88
+ - `install`: Clone the monorepo, materialize SHARED + GENERATED
89
+ surfaces, write the three MCP-config files, run `init-state` to
90
+ provision `<target>/.task-state/handoff.db` (skipped under
91
+ `--no-mcp-servers`), set `core.hooksPath`, and write the overlay
92
+ manifest.
93
+ - `update`: Re-run install at a new `--remote-ref`; refresh GENERATED
94
+ surfaces and, optionally, configs.
95
+ - `status`: Print a summary of the installed overlay manifest. When
96
+ the install registered MCP servers, also reports the resolved
97
+ `state_dir` / `db_path` / `exports_dir` / `schema_version` via
98
+ `init-state --check`.
99
+ - `doctor`: Detect drift in SHARED, GENERATED, config, and
100
+ initialized-state surfaces. Flags missing `.task-state/handoff.db`
101
+ as `state_drift` only when the manifest recorded `.mcp.json`. Exit
102
+ `1` when drift exists.
103
+ - `repair`: Restore drifted surfaces flagged by `doctor`.
104
+
105
+ See [`docs/CONSUMER.md`](https://github.com/darce/workstate/blob/main/docs/CONSUMER.md)
106
+ for the consumer-facing walkthrough (upgrade, drift handling, skill
107
+ overrides, the `current_task_auto_regen` migration note).
108
+
109
+ ## Surfaces written by `install`
110
+
111
+ The canonical source of truth for bootstrap-managed surfaces is the
112
+ installer implementation in
113
+ `src/workstate_bootstrap/install.py` (`SHARED_SURFACES` and
114
+ `GENERATED_SURFACES`). Keep this table aligned with those constants.
115
+
116
+ | Surface | Source | Layer |
117
+ | ------------------------------------ | ---------- | ----------- |
118
+ | `scripts/hooks/` | shared | symlink |
119
+ | `.github/hooks/` | shared | symlink |
120
+ | `docs/agentic/contracts/` | shared | symlink |
121
+ | `docs/agentic/rules/` | shared | symlink |
122
+ | `Makefile.d/` non-excluded children | shared | carved dir |
123
+ | `scripts/workstate/` non-excluded children | shared | carved dir |
124
+ | `.github/prompts/` | generated | real dir |
125
+ | `.agentic/generated/plugins/workstate-system/base/` | generated | real dir |
126
+ | `.agentic/generated/plugins/workstate-system/effective/` | generated | real dir |
127
+ | `.mcp.json` | generated | real file |
128
+ | `.vscode/mcp.json` | generated | real file |
129
+ | `.codex/config.toml` | generated | real file |
130
+ | `core.hooksPath` git config | generated | git config |
131
+ | `.task-state/handoff.db` | runtime | sqlite |
132
+ | `.task-state/exports/` | runtime | dir |
133
+ | `.agentic/remote/` | bootstrap | git clone |
134
+ | `.workstate-bootstrap.json` | bootstrap | manifest |
135
+
136
+ `.task-state/` is provisioned by the handoff server's `init-state`
137
+ subcommand at install time and is gitignored — each fresh checkout
138
+ regenerates it through `workstate-bootstrap install`.
139
+
140
+ ## Defaults
141
+
142
+ - `--profile` defaults to `all`, which materializes the full surface
143
+ set: generated Copilot prompts, Claude/Codex plugin trees, shared
144
+ overlay surfaces, and the lifecycle hoist
145
+ (`Makefile.d/lifecycle.mk` plus the sentinel-bracketed `-include`
146
+ block in the consumer `Makefile`). Pass `--profile minimal` for a
147
+ clone-only install with no surfaces, or `--profile lifecycle` for
148
+ just the lifecycle runner and Makefile fragment. The active profile
149
+ is recorded in `.workstate-bootstrap.json` under `"profile"`.
150
+ - `--remote-url` defaults to `git@github.com:darce/workstate.git`.
151
+ - `--remote-ref` defaults to `main` (override with a release tag like `v0.1.0`).
152
+ - `--mcp-servers` defaults to the built-in managed map registering
153
+ `mcp-workstate-handoff` and `mcp-workstate-orchestrator` via `uvx` with
154
+ `--workspace-root . serve-stdio`, so Codex, VS Code, and Claude
155
+ clients start real MCP stdio servers from the generated config.
156
+ Pass a JSON file path to override; pass `--no-mcp-servers` to skip
157
+ the three config writers entirely.
158
+ - Plugin overrides are auto-discovered at
159
+ `workstate-overrides/workstate-system/` when that root contains an
160
+ `overrides.yaml` manifest. Use `--plugin-overrides <path>` on
161
+ `install`, `update`, `doctor`, or `repair` for a non-default root;
162
+ bootstrap records that path so later update/doctor/repair runs reuse
163
+ it. Override-aware installs generate effective plugin trees under
164
+ `.agentic/generated/plugins/workstate-system/effective/{claude,codex}`
165
+ and point marketplace pins at those generated trees.
166
+ - `install` and `update` preserve plugin override files by default.
167
+ `--reset-overrides` is the explicit destructive path; it removes only
168
+ the resolved override root, refuses dirty git worktrees unless
169
+ `--backup` is supplied, and archives backups under
170
+ `.agentic/override-backups/<timestamp>/` before removal.
171
+
172
+ ## Development
173
+
174
+ Tests live under `tests/`. From the monorepo root:
175
+
176
+ ```bash
177
+ cd packages/workstate-bootstrap
178
+ PYTHONPATH=.:src:../workstate-protocol/src pytest tests -q
179
+ ```
@@ -0,0 +1,160 @@
1
+ # workstate-bootstrap
2
+
3
+ Pip-installable CLI that hoists the shared workstate-system surface
4
+ (typed protocol, two MCP servers, hooks, skills, generated agent
5
+ workflows) into consumer repositories. Lives inside
6
+ [`darce/workstate`](https://github.com/darce/workstate).
7
+
8
+ Consumers run `workstate-bootstrap install --target <path>` once; it
9
+ clones the monorepo, materializes the overlay, and registers both
10
+ managed MCP servers (`mcp-workstate-handoff`, `mcp-workstate-orchestrator`)
11
+ across `.mcp.json`, `.vscode/mcp.json`, and `.codex/config.toml`. No
12
+ hand-edits required.
13
+
14
+ ## Install
15
+
16
+ ### From PyPI (recommended)
17
+
18
+ ```bash
19
+ uvx --from workstate-bootstrap workstate-bootstrap install --target /path/to/your/repo
20
+ # or, persistent:
21
+ uv tool install workstate-bootstrap
22
+ ```
23
+
24
+ ### From the monorepo source tree (development)
25
+
26
+ ```bash
27
+ cd packages/workstate-bootstrap
28
+ python -m pip install -e ".[dev]"
29
+ ```
30
+
31
+ ### Direct from git (private-repo phase, before PyPI release)
32
+
33
+ One-shot (no install — fetches each invocation):
34
+
35
+ ```bash
36
+ uvx --from "git+https://github.com/darce/workstate@workstate-bootstrap-v0.2.1#subdirectory=packages/workstate-bootstrap" \
37
+ workstate-bootstrap install \
38
+ --target /path/to/your/repo
39
+ ```
40
+
41
+ Persistent (recommended once you start running `status` / `doctor`
42
+ regularly — installs `workstate-bootstrap` onto `$PATH`):
43
+
44
+ ```bash
45
+ uv tool install "git+https://github.com/darce/workstate@workstate-bootstrap-v0.2.1#subdirectory=packages/workstate-bootstrap"
46
+ # then:
47
+ workstate-bootstrap status --target /path/to/your/repo
48
+ workstate-bootstrap doctor --target /path/to/your/repo
49
+ # upgrade later:
50
+ uv tool upgrade workstate-bootstrap
51
+ ```
52
+
53
+ > **Hardlink warning on first install?** If you see
54
+ > `Failed to hardlink files; falling back to full copy`, your `uv`
55
+ > cache and tool dir live on different filesystems. The install still
56
+ > succeeds; silence the warning with `export UV_LINK_MODE=copy` in
57
+ > your shell profile.
58
+
59
+ ## Subcommands
60
+
61
+ ```text
62
+ workstate-bootstrap install --target <path> [--remote-ref <tag>] [--mcp-servers <default|path>] [--no-mcp-servers]
63
+ workstate-bootstrap update --target <path> --remote-ref <tag>
64
+ workstate-bootstrap status --target <path>
65
+ workstate-bootstrap doctor --target <path> [--mcp-servers <default|path>]
66
+ workstate-bootstrap repair --target <path> [--force-dirty] [--mcp-servers <default|path>]
67
+ ```
68
+
69
+ - `install`: Clone the monorepo, materialize SHARED + GENERATED
70
+ surfaces, write the three MCP-config files, run `init-state` to
71
+ provision `<target>/.task-state/handoff.db` (skipped under
72
+ `--no-mcp-servers`), set `core.hooksPath`, and write the overlay
73
+ manifest.
74
+ - `update`: Re-run install at a new `--remote-ref`; refresh GENERATED
75
+ surfaces and, optionally, configs.
76
+ - `status`: Print a summary of the installed overlay manifest. When
77
+ the install registered MCP servers, also reports the resolved
78
+ `state_dir` / `db_path` / `exports_dir` / `schema_version` via
79
+ `init-state --check`.
80
+ - `doctor`: Detect drift in SHARED, GENERATED, config, and
81
+ initialized-state surfaces. Flags missing `.task-state/handoff.db`
82
+ as `state_drift` only when the manifest recorded `.mcp.json`. Exit
83
+ `1` when drift exists.
84
+ - `repair`: Restore drifted surfaces flagged by `doctor`.
85
+
86
+ See [`docs/CONSUMER.md`](https://github.com/darce/workstate/blob/main/docs/CONSUMER.md)
87
+ for the consumer-facing walkthrough (upgrade, drift handling, skill
88
+ overrides, the `current_task_auto_regen` migration note).
89
+
90
+ ## Surfaces written by `install`
91
+
92
+ The canonical source of truth for bootstrap-managed surfaces is the
93
+ installer implementation in
94
+ `src/workstate_bootstrap/install.py` (`SHARED_SURFACES` and
95
+ `GENERATED_SURFACES`). Keep this table aligned with those constants.
96
+
97
+ | Surface | Source | Layer |
98
+ | ------------------------------------ | ---------- | ----------- |
99
+ | `scripts/hooks/` | shared | symlink |
100
+ | `.github/hooks/` | shared | symlink |
101
+ | `docs/agentic/contracts/` | shared | symlink |
102
+ | `docs/agentic/rules/` | shared | symlink |
103
+ | `Makefile.d/` non-excluded children | shared | carved dir |
104
+ | `scripts/workstate/` non-excluded children | shared | carved dir |
105
+ | `.github/prompts/` | generated | real dir |
106
+ | `.agentic/generated/plugins/workstate-system/base/` | generated | real dir |
107
+ | `.agentic/generated/plugins/workstate-system/effective/` | generated | real dir |
108
+ | `.mcp.json` | generated | real file |
109
+ | `.vscode/mcp.json` | generated | real file |
110
+ | `.codex/config.toml` | generated | real file |
111
+ | `core.hooksPath` git config | generated | git config |
112
+ | `.task-state/handoff.db` | runtime | sqlite |
113
+ | `.task-state/exports/` | runtime | dir |
114
+ | `.agentic/remote/` | bootstrap | git clone |
115
+ | `.workstate-bootstrap.json` | bootstrap | manifest |
116
+
117
+ `.task-state/` is provisioned by the handoff server's `init-state`
118
+ subcommand at install time and is gitignored — each fresh checkout
119
+ regenerates it through `workstate-bootstrap install`.
120
+
121
+ ## Defaults
122
+
123
+ - `--profile` defaults to `all`, which materializes the full surface
124
+ set: generated Copilot prompts, Claude/Codex plugin trees, shared
125
+ overlay surfaces, and the lifecycle hoist
126
+ (`Makefile.d/lifecycle.mk` plus the sentinel-bracketed `-include`
127
+ block in the consumer `Makefile`). Pass `--profile minimal` for a
128
+ clone-only install with no surfaces, or `--profile lifecycle` for
129
+ just the lifecycle runner and Makefile fragment. The active profile
130
+ is recorded in `.workstate-bootstrap.json` under `"profile"`.
131
+ - `--remote-url` defaults to `git@github.com:darce/workstate.git`.
132
+ - `--remote-ref` defaults to `main` (override with a release tag like `v0.1.0`).
133
+ - `--mcp-servers` defaults to the built-in managed map registering
134
+ `mcp-workstate-handoff` and `mcp-workstate-orchestrator` via `uvx` with
135
+ `--workspace-root . serve-stdio`, so Codex, VS Code, and Claude
136
+ clients start real MCP stdio servers from the generated config.
137
+ Pass a JSON file path to override; pass `--no-mcp-servers` to skip
138
+ the three config writers entirely.
139
+ - Plugin overrides are auto-discovered at
140
+ `workstate-overrides/workstate-system/` when that root contains an
141
+ `overrides.yaml` manifest. Use `--plugin-overrides <path>` on
142
+ `install`, `update`, `doctor`, or `repair` for a non-default root;
143
+ bootstrap records that path so later update/doctor/repair runs reuse
144
+ it. Override-aware installs generate effective plugin trees under
145
+ `.agentic/generated/plugins/workstate-system/effective/{claude,codex}`
146
+ and point marketplace pins at those generated trees.
147
+ - `install` and `update` preserve plugin override files by default.
148
+ `--reset-overrides` is the explicit destructive path; it removes only
149
+ the resolved override root, refuses dirty git worktrees unless
150
+ `--backup` is supplied, and archives backups under
151
+ `.agentic/override-backups/<timestamp>/` before removal.
152
+
153
+ ## Development
154
+
155
+ Tests live under `tests/`. From the monorepo root:
156
+
157
+ ```bash
158
+ cd packages/workstate-bootstrap
159
+ PYTHONPATH=.:src:../workstate-protocol/src pytest tests -q
160
+ ```
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.21"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "workstate-bootstrap"
7
+ version = "0.5.2"
8
+ description = "Bootstrap CLI that hoists the shared workstate-system surface into consumer repos."
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = { text = "Proprietary" }
12
+ authors = [{ name = "darce" }]
13
+ dependencies = ["tomlkit>=0.13", "pyyaml>=6", "workstate-protocol>=0.1.4,<0.2.0"]
14
+
15
+ [project.scripts]
16
+ workstate-bootstrap = "workstate_bootstrap.cli:main"
17
+
18
+ [project.urls]
19
+ Homepage = "https://github.com/darce/workstate"
20
+ Source = "https://github.com/darce/workstate/tree/main/packages/workstate-bootstrap"
21
+ Documentation = "https://github.com/darce/workstate/blob/main/docs/CONSUMER.md"
22
+ Issues = "https://github.com/darce/workstate/issues"
23
+
24
+ [project.optional-dependencies]
25
+ dev = ["pytest>=8", "mcp-workstate-handoff; python_version >= '3.12'"]
26
+
27
+ [tool.uv.sources]
28
+ mcp-workstate-handoff = { path = "../mcp-workstate-handoff", editable = true }
29
+ workstate-protocol = { path = "../workstate-protocol", editable = true }
30
+
31
+ [tool.hatch.build.targets.wheel]
32
+ packages = ["src/workstate_bootstrap"]
33
+
34
+ [tool.pytest.ini_options]
35
+ testpaths = ["tests"]
36
+ addopts = "-ra"
@@ -0,0 +1,6 @@
1
+ """workstate-bootstrap: hoist the shared workstate-system surface into consumer repos."""
2
+
3
+ from workstate_bootstrap.install import install
4
+
5
+ __all__ = ["install"]
6
+ __version__ = "0.5.2"
@@ -0,0 +1,5 @@
1
+ """Allow ``python -m workstate_bootstrap``."""
2
+
3
+ from workstate_bootstrap.cli import main
4
+
5
+ raise SystemExit(main())