Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"name": "projectstore",
"displayName": "projectstore",
"description": "📚 Your agent runs the project through a verified loop: task → artifact (ADR · spec · epic · story) → adversarial critic → backlog → planner → reviewer → done. Plain markdown in an Obsidian-friendly vault, every write approved by you — and any model can pick the project up tomorrow.",
"version": "0.28.2",
"version": "0.29.0",
"author": {
"name": "Evgenii Konev",
"email": "[email protected]",
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "projectstore",
"displayName": "projectstore",
"version": "0.28.2",
"version": "0.29.0",
"description": "Your agent runs the project through a verified loop: task → artifact (ADR / spec / epic / story) → adversarial critic → backlog → planner → reviewer → done. Plain markdown in git — any model can pick the project up tomorrow.",
"author": {
"name": "Evgenii Konev @ SmartAndPoint",
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ Contributors: `git clone` this repo, then `claude --plugin-dir ./ProjectStore`.
npx projectstore-claude install --project "$PWD"
```

The same tree is published to npm as [`projectstore`](https://www.npmjs.com/package/projectstore) — one source package carrying every harness's manifest — and `projectstore-claude` is its Claude Code shell: the core pinned at the same version and bundled inside, the harness fixed, so the one command has the same shape on every harness. It registers the plugin with Claude Code: it writes a small local marketplace of its own under your Claude home, then drives `claude plugin marketplace add` / `plugin install` **at local scope**, so the registration lands in this checkout's `.claude/settings.local.json` and nowhere else. Every host command is printed before it runs; naming the harness is the confirmation. Restart Claude Code afterwards. A git-marketplace copy already enabled for the checkout is silenced there (not globally) so the plugin does not load twice; `uninstall` turns it back on. Pin or upgrade with `npx projectstore-claude@<version> upgrade --project "$PWD"` — the version you name is the version you run. The core's low-level form, `npx projectstore <verb> --harness claude-code …`, is exactly what the shell runs. bun works the same on the packed bin.
The same tree is published to npm as [`projectstore`](https://www.npmjs.com/package/projectstore) — one source package carrying every harness's manifest — and `projectstore-claude` is its Claude Code shell: the core pinned at the same version and bundled inside, the harness fixed, so the one command has the same shape on every harness. It registers the plugin with Claude Code: it writes a small local marketplace of its own under your Claude home, then drives `claude plugin marketplace add` / `plugin install` **at local scope**, so the registration lands in this checkout's `.claude/settings.local.json` and nowhere else. It prints its plan first — every file it writes and every host command, verbatim — and at a terminal asks `Apply N changes? [Y/n]`; then it shows each step as it runs and what to do next. Without a terminal (a script, CI, an agent's tool) naming the harness is the confirmation. `plan` prints the same plan and writes nothing; `--verbose` adds every row's reasoning; `npx projectstore-claude <verb> --help` lists a verb's options with examples. Restart Claude Code afterwards. A git-marketplace copy already enabled for the checkout is silenced there (not globally) so the plugin does not load twice; `uninstall` turns it back on. Pin or upgrade with `npx projectstore-claude@<version> upgrade --project "$PWD"` — the version you name is the version you run. The core's low-level form, `npx projectstore <verb> --harness claude-code …`, is exactly what the shell runs. bun works the same on the packed bin.

**Codex has its own shell with the same one-command shape:**
`npx projectstore-codex install --project "$PWD"`. It carries a Codex
Expand All @@ -120,7 +120,7 @@ The package also carries a `bin`. Without a session — in CI, or in a shell —

```
npx projectstore doctor --json
npx projectstore install --harness claude-code # the low-level form the shell runs: previews, then writes the agents block and the status line; naming the harness is the confirmation, there is no --yes
npx projectstore install --harness claude-code # the low-level form the shell runs: shows the plan, asks at a terminal, then writes; without a terminal naming the harness is the confirmation — there is no --yes
npx projectstore reconcile --write --only kanban
```

Expand Down
9 changes: 5 additions & 4 deletions adapters/codex/skills/projectstore-agents/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ You are managing ProjectStore's Codex agent integration. Require a bound project

## register / unregister

Preview the requested change and ask for explicit approval. On approval, run the
core's `install` or `uninstall` verb with `--harness codex --surface
agents_block --project "$PWD"`. Print its output verbatim. Never edit the
managed block by hand.
Preview the requested change with `plan --harness codex --surface agents_block
--project "$PWD"` and ask for explicit approval. On approval, run the core's
`install` or `uninstall` verb with `--harness codex --surface agents_block
--project "$PWD" --json` — `--json` never waits on a terminal's question — and
report the envelope's result. Never edit the managed block by hand.

## status

Expand Down
4 changes: 3 additions & 1 deletion adapters/codex/skills/projectstore-doctor/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ arguments and `--json`. Summarize every finding without re-deriving it.
When `--fix` is absent, remain read-only. When it is present, separate fixes
by owner: derived vault views use `$projectstore-reconcile`; Codex plugin or
agents-block drift uses the core's `upgrade --harness codex` path. Preview
each mutation and ask for explicit approval before running it. Unsupported
each mutation with `plan --harness codex` and ask for explicit approval before
running it; then run `upgrade --harness codex --json`, whose envelope is the
result — `--json` never waits on a terminal's question. Unsupported
surfaces remain unsupported; do not create host configuration by hand. Never
claim a fix after a non-zero exit.
3 changes: 3 additions & 0 deletions harnesses/claude-code.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
"/plugin marketplace add SmartAndPoint/ProjectStore && /plugin install projectstore@SmartAndPoint (git marketplace, user-wide)",
"restart Claude Code"
],
"next": [
"restart Claude Code in this project"
],
"notes": [
"Git marketplace only: auto-update is OFF by default for third-party plugins: /plugin -> Marketplaces -> SmartAndPoint -> toggle auto-update. The npm registration updates when you run `npx projectstore-claude upgrade --project <dir>`.",
"Pin a git-marketplace release with: /plugin marketplace add SmartAndPoint/ProjectStore#<tag>; pin the npm registration with npx projectstore-claude@<version>.",
Expand Down
4 changes: 4 additions & 0 deletions harnesses/codex.json
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,10 @@
"restart Codex and approve the ProjectStore hooks when prompted",
"run `$projectstore-bind <vault-path>` in Codex"
],
"next": [
"restart Codex from a terminal and approve the ProjectStore hooks when it asks",
"in an unbound project, run `$projectstore-bind <vault-path>` in Codex"
],
"notes": [
"The installation is user-global because Codex's marketplace, plugin row and cache live in CODEX_HOME; the AGENTS.md block is project-local.",
"Upgrade with `npx projectstore-codex@<version> upgrade --project \"$PWD\"`; the named package version is also the plugin version.",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "projectstore",
"version": "0.28.2",
"version": "0.29.0",
"description": "Your agent runs the project through a verified loop: task → artifact (ADR / spec / epic / story) → adversarial critic → backlog → planner → reviewer → done. Plain markdown in git — any model can pick the project up tomorrow.",
"keywords": [
"project-management",
Expand Down
23 changes: 14 additions & 9 deletions packaging/shells.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,10 @@ export function renderShellBin(shell, verbs) {
// \`--harness ${shell.harness}\` inserted after a verb that takes it. Every other
// argument passes through, so \`${shell.name} <verb> …\` is exactly
// \`projectstore <verb> --harness ${shell.harness} …\` — the same preview, the
// same files, the same exit code. Naming the shell is the confirmation the
// core's install gate asks for, exactly as naming --harness is.
// same files, the same exit code. Naming the shell names the harness, exactly
// as --harness does: without a terminal that is the confirmation the core's
// install gate asks for; at a terminal the core shows the plan and asks (the
// install spec, contract 9 as amended 2026-10-04).
import { existsSync } from "node:fs";
import { spawnSync } from "node:child_process";
import { constants as osConstants } from "node:os";
Expand Down Expand Up @@ -258,17 +260,20 @@ if (!core) {
process.stderr.write(\`\${SHELL}: \${fixed.error}\\n\`);
process.exitCode = 2;
} else {
// stdio inherited: the core's install gate asks on a terminal and refuses
// without one, so the child must see the real stdin and stdout. No
// timeout — the child waits on a human at the preview. exitCode, not
// exit(): the core's own bin says why (a pending write on a pipe).
// stdio inherited: the core's install gate shows the plan and asks on a
// terminal, and refuses a bare run without one, so the child must see the
// real stdin and stdout. No timeout — the child waits on a human at the
// question. exitCode, not exit(): the core's own bin says why (a pending
// write on a pipe). PROJECTSTORE_SHELL lets the core's --help speak this
// shell's name; nothing the core plans or writes reads it.
const r = spawnSync(process.execPath, [core, ...fixed.argv], {
stdio: "inherit",
env: { ...process.env, PROJECTSTORE_DISTRIBUTION_ROOT: root },
env: { ...process.env, PROJECTSTORE_DISTRIBUTION_ROOT: root, PROJECTSTORE_SHELL: SHELL },
});
if (r.error) process.stderr.write(\`\${SHELL}: \${r.error.message}\\n\`);
// A signal is relayed the shell way (128 + its number): Ctrl-C at the
// preview is 130 here as it would be on the core itself.
// A signal is relayed the shell way (128 + its number): the core reads
// its answer in the terminal's line mode, so Ctrl-C at the question is a
// real SIGINT — 130 here as it would be on the core itself.
process.exitCode = r.status ?? (r.signal ? 128 + (osConstants.signals[r.signal] || 0) : 2);
}
}
Expand Down
4 changes: 3 additions & 1 deletion packaging/shells/projectstore-claude/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ The Claude Code installer for [projectstore](https://www.npmjs.com/package/proje
npx projectstore-claude install --project "$PWD"
```

It registers the plugin for that checkout at the host's local scope, previews every write and every host command before it runs, and asks for nothing else — naming the shell is the confirmation. Restart Claude Code afterwards.
It registers the plugin for that checkout at the host's local scope. It prints its plan first — every write and every host command, verbatim — and at a terminal asks `Apply N changes? [Y/n]` before anything runs; then each step as it runs, and what to do next. Without a terminal (a script, CI, an agent's tool) naming the shell is the confirmation; `--json` never asks. Restart Claude Code afterwards.

- See before you write: `npx projectstore-claude plan --project "$PWD"` prints the same plan and writes nothing; `--verbose` adds every row's reasoning; `npx projectstore-claude <verb> --help` lists a verb's options with examples.

- Upgrade, or pin: `npx projectstore-claude@<version> upgrade --project "$PWD"` — the version you name is the version you run.
- Uninstall: `npx projectstore-claude uninstall --project "$PWD"` — forgets the registration for that checkout and nothing else; your vault is plain markdown and stays yours.
Expand Down
23 changes: 14 additions & 9 deletions packaging/shells/projectstore-claude/bin/projectstore-claude.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
// `--harness claude-code` inserted after a verb that takes it. Every other
// argument passes through, so `projectstore-claude <verb> …` is exactly
// `projectstore <verb> --harness claude-code …` — the same preview, the
// same files, the same exit code. Naming the shell is the confirmation the
// core's install gate asks for, exactly as naming --harness is.
// same files, the same exit code. Naming the shell names the harness, exactly
// as --harness does: without a terminal that is the confirmation the core's
// install gate asks for; at a terminal the core shows the plan and asks (the
// install spec, contract 9 as amended 2026-10-04).
import { existsSync } from "node:fs";
import { spawnSync } from "node:child_process";
import { constants as osConstants } from "node:os";
Expand Down Expand Up @@ -72,17 +74,20 @@ if (!core) {
process.stderr.write(`${SHELL}: ${fixed.error}\n`);
process.exitCode = 2;
} else {
// stdio inherited: the core's install gate asks on a terminal and refuses
// without one, so the child must see the real stdin and stdout. No
// timeout — the child waits on a human at the preview. exitCode, not
// exit(): the core's own bin says why (a pending write on a pipe).
// stdio inherited: the core's install gate shows the plan and asks on a
// terminal, and refuses a bare run without one, so the child must see the
// real stdin and stdout. No timeout — the child waits on a human at the
// question. exitCode, not exit(): the core's own bin says why (a pending
// write on a pipe). PROJECTSTORE_SHELL lets the core's --help speak this
// shell's name; nothing the core plans or writes reads it.
const r = spawnSync(process.execPath, [core, ...fixed.argv], {
stdio: "inherit",
env: { ...process.env, PROJECTSTORE_DISTRIBUTION_ROOT: root },
env: { ...process.env, PROJECTSTORE_DISTRIBUTION_ROOT: root, PROJECTSTORE_SHELL: SHELL },
});
if (r.error) process.stderr.write(`${SHELL}: ${r.error.message}\n`);
// A signal is relayed the shell way (128 + its number): Ctrl-C at the
// preview is 130 here as it would be on the core itself.
// A signal is relayed the shell way (128 + its number): the core reads
// its answer in the terminal's line mode, so Ctrl-C at the question is a
// real SIGINT — 130 here as it would be on the core itself.
process.exitCode = r.status ?? (r.signal ? 128 + (osConstants.signals[r.signal] || 0) : 2);
}
}
4 changes: 2 additions & 2 deletions packaging/shells/projectstore-claude/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "projectstore-claude",
"version": "0.28.2",
"version": "0.29.0",
"description": "Installs projectstore for Claude Code from npm: the core pinned and bundled, the harness fixed — npx projectstore-claude install --project \"$PWD\".",
"keywords": [
"projectstore",
Expand Down Expand Up @@ -37,7 +37,7 @@
"README.md"
],
"dependencies": {
"projectstore": "=0.28.2"
"projectstore": "=0.29.0"
},
"bundleDependencies": [
"projectstore"
Expand Down
1 change: 1 addition & 0 deletions packaging/shells/projectstore-claude/packlist.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"node_modules/projectstore/scripts/statusline.mjs",
"node_modules/projectstore/scripts/story-section.mjs",
"node_modules/projectstore/scripts/surfaces.mjs",
"node_modules/projectstore/scripts/term.mjs",
"node_modules/projectstore/scripts/tokens.mjs",
"node_modules/projectstore/scripts/touch-session.mjs",
"node_modules/projectstore/scripts/version-guard.mjs",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "projectstore",
"version": "0.28.2",
"version": "0.29.0",
"description": "Your agent runs the project through a verified loop: task → artifact (ADR / spec / epic / story) → adversarial critic → backlog → planner → reviewer → done. Plain markdown in git — any model can pick the project up tomorrow.",
"author": {
"name": "Evgenii Konev",
Expand Down
2 changes: 1 addition & 1 deletion packaging/shells/projectstore-codex/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ From a terminal in your project:
npx projectstore-codex install --project "$PWD"
```

The installer previews every mutation, stages a stable local marketplace under `CODEX_HOME`, asks Codex's own CLI to install the plugin, and verifies the materialised cache by version and payload digest. Restart Codex, approve the ProjectStore hooks when prompted, then run `$projectstore-bind <vault-path>`. Codex picks up hook changes late: a release that changes hooks may take effect only in the session after next.
The installer prints its plan first — every mutation and every Codex command, verbatim — and at a terminal asks `Apply N changes? [Y/n]` (without one, naming the shell is the confirmation; `--json` never asks). It then stages a stable local marketplace under `CODEX_HOME`, asks Codex's own CLI to install the plugin, verifies the materialised cache by version and payload digest, and says what to do next. `npx projectstore-codex plan --project "$PWD"` prints the same plan and writes nothing; `--verbose` adds every row's reasoning; `<verb> --help` lists a verb's options with examples. Restart Codex, approve the ProjectStore hooks when prompted, then run `$projectstore-bind <vault-path>`. Codex picks up hook changes late: a release that changes hooks may take effect only in the session after next.

Upgrade with `npx projectstore-codex@<version> upgrade --project "$PWD"`. Project uninstall leaves the user-global Codex plugin in place; `uninstall --global` is the explicit machine-wide removal.

Expand Down
23 changes: 14 additions & 9 deletions packaging/shells/projectstore-codex/bin/projectstore-codex.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
// `--harness codex` inserted after a verb that takes it. Every other
// argument passes through, so `projectstore-codex <verb> …` is exactly
// `projectstore <verb> --harness codex …` — the same preview, the
// same files, the same exit code. Naming the shell is the confirmation the
// core's install gate asks for, exactly as naming --harness is.
// same files, the same exit code. Naming the shell names the harness, exactly
// as --harness does: without a terminal that is the confirmation the core's
// install gate asks for; at a terminal the core shows the plan and asks (the
// install spec, contract 9 as amended 2026-10-04).
import { existsSync } from "node:fs";
import { spawnSync } from "node:child_process";
import { constants as osConstants } from "node:os";
Expand Down Expand Up @@ -72,17 +74,20 @@ if (!core) {
process.stderr.write(`${SHELL}: ${fixed.error}\n`);
process.exitCode = 2;
} else {
// stdio inherited: the core's install gate asks on a terminal and refuses
// without one, so the child must see the real stdin and stdout. No
// timeout — the child waits on a human at the preview. exitCode, not
// exit(): the core's own bin says why (a pending write on a pipe).
// stdio inherited: the core's install gate shows the plan and asks on a
// terminal, and refuses a bare run without one, so the child must see the
// real stdin and stdout. No timeout — the child waits on a human at the
// question. exitCode, not exit(): the core's own bin says why (a pending
// write on a pipe). PROJECTSTORE_SHELL lets the core's --help speak this
// shell's name; nothing the core plans or writes reads it.
const r = spawnSync(process.execPath, [core, ...fixed.argv], {
stdio: "inherit",
env: { ...process.env, PROJECTSTORE_DISTRIBUTION_ROOT: root },
env: { ...process.env, PROJECTSTORE_DISTRIBUTION_ROOT: root, PROJECTSTORE_SHELL: SHELL },
});
if (r.error) process.stderr.write(`${SHELL}: ${r.error.message}\n`);
// A signal is relayed the shell way (128 + its number): Ctrl-C at the
// preview is 130 here as it would be on the core itself.
// A signal is relayed the shell way (128 + its number): the core reads
// its answer in the terminal's line mode, so Ctrl-C at the question is a
// real SIGINT — 130 here as it would be on the core itself.
process.exitCode = r.status ?? (r.signal ? 128 + (osConstants.signals[r.signal] || 0) : 2);
}
}
4 changes: 2 additions & 2 deletions packaging/shells/projectstore-codex/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "projectstore-codex",
"version": "0.28.2",
"version": "0.29.0",
"description": "ProjectStore for Codex: portable project memory, rendered workflow skills and lifecycle hooks, with the core pinned and bundled.",
"keywords": [
"projectstore",
Expand Down Expand Up @@ -40,7 +40,7 @@
"hooks/"
],
"dependencies": {
"projectstore": "=0.28.2"
"projectstore": "=0.29.0"
},
"bundleDependencies": [
"projectstore"
Expand Down
Loading
Loading