diff --git a/docs/articles/devto/2026-10-15-a-compliance-monitor-that-does-not-busywork.md b/docs/articles/devto/2026-10-15-a-compliance-monitor-that-does-not-busywork.md new file mode 100644 index 00000000..24d8f44c --- /dev/null +++ b/docs/articles/devto/2026-10-15-a-compliance-monitor-that-does-not-busywork.md @@ -0,0 +1,98 @@ +--- +title: A compliance monitor that does not busywork +published: false +description: OpenSpec Workbench now ships a versioned catalogue of rules, checks that run only when the host is idle, and findings that explain what is wrong without moving a single file. +tags: openspec, devtools, compliance, opensource +cover_image: https://raw.githubusercontent.com/VeryComplexAndLongName/OpenSpec-UI/main/docs/articles/site/a-compliance-monitor-that-does-not-busywork/cover.jpg +canonical_url: https://openspec-ui.dev/articles/a-compliance-monitor-that-does-not-busywork/ +--- + +*First published on [openspec-ui.dev](https://openspec-ui.dev/articles/a-compliance-monitor-that-does-not-busywork/).* + +OpenSpec Workbench initializes repositories and runs agents on changes. It +did not, until now, check that its own runtime files are ignored, or that +its repository rules are consistent. A compliance monitor has been added to +the shared core, and it does three things that matter: it keeps a versioned +catalogue of rules, it runs only when the host reports idle, and it reports +findings without moving or deleting anything. + +## The catalogue, versioned and evidence-linked + +Every rule in the catalogue carries a stable identifier, a description of +what it checks, and metadata about the check's cost and whether it supports +automatic repair. Each finding is linked back to the rule that produced it +and to the evidence that triggered it, so you can trace a finding to the +exact check and the exact file or state that caused it. + +The catalogue is versioned. When a rule changes, the new version is applied +to future checks, and old findings remain linked to the version that +produced them. This matters when a rule's threshold is tightened or +relaxed: old findings do not retroactively become violations or pass. + +## What it checks, on initialization + +On explicit repository initialization, the monitor verifies that Workbench +runtime state is ignored by Git. It adds only the missing managed ignore +rule, preserving the rest of `.gitignore` exactly as you wrote it. Nothing +is overwritten. + +It also checks Workbench runtime files in the main checkout and in +worktrees. It identifies untracked or visible state and explains the +expected root for each state kind without moving or deleting it. A run +journal in `.openspec-ui/` is expected to be untracked; a lease file in the +main checkout is expected to be ignored. The monitor says which is which, +and why. + +## Grouping, deduplication and shadow detection + +When the same change id appears in multiple worktrees, the monitor groups +them as one logical change and reports the count. It flags a change id +present in both active and archive trees, an archived change left in a +stale worktree, or a shadow copy in main beside its owning worktree. The +Pipeline card count is reconciled with the Changes list, and active changes +missing from the OpenSpec README index are flagged with a suggested link, +not an automatic edit. + +## Per-rule reactions and a periodic schedule + +Each rule accepts one of three response settings: `autorepair`, `advice` +or `none`. `autorepair` applies a fix without asking; `advice` produces a +finding with a suggested action; `none` records the finding silently. A +global periodic-monitor switch enables or disables the entire schedule. + +The monitor runs one bounded batch only after the host reports idle and no +mutating Workbench run is active. It measures each check's elapsed time, +schedules by due date and conservative cost, and spreads expensive checks +across later idle windows. Nothing runs as a separate OS daemon. + +## Process ledger and orphan detection + +A companion capability, the process ledger, records a synchronous snapshot +for every process spawned by Workbench: PID, OS start time, executable, +hostname, cwd, change, and a secret-free command-line hash. Records are +marked exited on normal close and kept durable across host restarts, keyed +by canonical repository identity and hostname. + +Before any kill, the snapshot is re-verified against the operating system. +Orphaned and overdue processes are surfaced as read-only Compliance +findings. An explicit, confirmable kill lives in the existing recovery +surface, never in Compliance itself. The two capabilities share the same +catalogue but never cross their boundaries: Compliance explains, recovery +acts. + +## What this deliberately does not do + +The monitor does not start a background daemon, does not modify source code, +does not run on every file change, and does not replace a linter or a +formatter. It checks Workbench's own runtime hygiene and the consistency of +its repository state. + +## Try it + +The code is at +[github.com/VeryComplexAndLongName/OpenSpec-UI](https://github.com/VeryComplexAndLongName/OpenSpec-UI), +where the repository and packages keep the name OpenSpec-UI. + +```bash +openspec-ui-cli compliance check --cwd . +``` diff --git a/docs/articles/devto/2026-10-20-local-models-can-now-search-the-web-and-fetch-pages.md b/docs/articles/devto/2026-10-20-local-models-can-now-search-the-web-and-fetch-pages.md new file mode 100644 index 00000000..bb1e4e5c --- /dev/null +++ b/docs/articles/devto/2026-10-20-local-models-can-now-search-the-web-and-fetch-pages.md @@ -0,0 +1,75 @@ +--- +title: Local models can now search the web and fetch pages +published: false +description: Two new shared core tools, search_web and fetch_webpage, let local-model agents consult a SearXNG endpoint and retrieve HTML pages as Markdown. No remote agents are changed. +tags: openspec, ai, local-llm, opensource +cover_image: https://raw.githubusercontent.com/VeryComplexAndLongName/OpenSpec-UI/main/docs/articles/site/local-models-can-now-search-the-web-and-fetch-pages/cover.jpg +canonical_url: https://openspec-ui.dev/articles/local-models-can-now-search-the-web-and-fetch-pages/ +--- + +*First published on [openspec-ui.dev](https://openspec-ui.dev/articles/local-models-can-now-search-the-web-and-fetch-pages/).* + +OpenSpec Workbench puts local-model behavior and its security controls in +the shared core, but until now neither local adapter could search the web +or fetch a source page. Two new shared core tools have been added: +`search_web` and `fetch_webpage`. They let local-model agents consult a +SearXNG endpoint and retrieve HTML pages as Markdown-backed JSON artifacts +that can be analyzed or passed to another agent. + +## What the tools do + +`search_web` sends a query to a SearXNG JSON endpoint and returns the +results as structured data. `fetch_webpage` retrieves a public HTTP(S) URL, +converts the article or main content to Markdown, writes every data table +as a Markdown table, and returns provenance, page metadata and timestamps +in JSON. + +Both tools are available to both local-model adapters: `local-llm` and +`local-llm-acp`. Remote agents are unchanged. The tools do not speak to +any vendor API; they speak only to the SearXNG instance you configure. + +## Configuration and bounds + +The single SearXNG instance is configured with the `OPENSPEC_UI_SEARXNG_URL` +environment variable. When search has not been configured, the tools return +an explicit error rather than failing silently or hanging. + +Page fetching is restricted to bounded public HTTP(S) HTML. Pages larger +than the configured bound are read up to the bound and the response says +so. Remote content is treated as untrusted data throughout the pipeline. + +## Why this matters for local models + +A local model is only as useful as the information it can bring to bear. +Before these tools, a local agent could reason about what was already in +its context window, but it could not look up a current fact or read a +source page. Now it can search for context and fetch the page that +contains it, all without sending data to a remote API. + +The tools return Markdown-backed JSON artifacts, not raw HTML. This means +the local model receives clean, structured content that fits into its +context window more efficiently, and that data tables are preserved as +Markdown tables rather than lost in markup noise. + +## What this deliberately does not do + +These tools are not a general-purpose web browser. They do not execute +JavaScript, they do not render CSS, and they do not interact with forms +or buttons. They search and fetch, convert to Markdown, and return. If a +page requires JavaScript to render its content, the fetch will return +whatever the server sends without execution. + +They also do not change the command or event protocol. No new transport +channels are opened, no new agent types are introduced. The tools are +exposed through the existing local-model adapters, and the environment +configuration is read by the shared core runner. + +## Try it + +The code is at +[github.com/VeryComplexAndLongName/OpenSpec-UI](https://github.com/VeryComplexAndLongName/OpenSpec-UI), +where the repository and packages keep the name OpenSpec-UI. + +```bash +OPENSPEC_UI_SEARXNG_URL=http://localhost:8080 openspec-ui-cli run --change my-change +``` diff --git a/docs/articles/devto/2026-10-25-the-agent-asks-the-operator-and-the-chain-waits.md b/docs/articles/devto/2026-10-25-the-agent-asks-the-operator-and-the-chain-waits.md new file mode 100644 index 00000000..92fdd19b --- /dev/null +++ b/docs/articles/devto/2026-10-25-the-agent-asks-the-operator-and-the-chain-waits.md @@ -0,0 +1,68 @@ +--- +title: The agent asks the operator, and the chain waits +published: false +description: An agent can now raise a question for the operator, the chain stops and waits, answers are kept in decisions.md, and the product's own agent asks in its turn from the start. +tags: openspec, ai, agents, opensource +cover_image: https://raw.githubusercontent.com/VeryComplexAndLongName/OpenSpec-UI/main/docs/articles/site/the-agent-asks-the-operator-and-the-chain-waits/cover.jpg +canonical_url: https://openspec-ui.dev/articles/the-agent-asks-the-operator-and-the-chain-waits/ +--- + +*First published on [openspec-ui.dev](https://openspec-ui.dev/articles/the-agent-asks-the-operator-and-the-chain-waits/).* + +An agent ended its run with four decisions it needed from the operator, +and the product offered no way to answer them. A chain would have gone on +to the next stage with them open. The owner decided the same day: questions +are caught, the run stops and waits, nothing goes on without an answer, the +answers are kept in the change's `decisions.md` and in the audit log, and +the product's own agent asks in its turn from the start. + +## The marker, the event and the command + +Every agent stage's instruction asks for `Question for the operator: <…>` +lines for decisions the agent needs. The product reads them as markers. +`local-llm-acp` gets an `ask_operator` tool that blocks its turn until +answered. + +A `question` event and an `answerQuestion` command are added to the +protocol. A `question` waiting kind appears in the run's status. A run +that asked waits instead of completing, in a chain or alone, under every +autonomy level. Once answered, the stage runs again with the answers — +`update` for propose and review, the same command otherwise. + +## Where answers live + +`openspec/changes//decisions.md` holds every question and answer. +The audit log records both. An agent run on a change with an open question +is refused. + +Questions are answered from the card, the AI panel, the Human-Only Inbox +and `openspec-ui-cli answer`. The card shows open questions with answer +fields; the panel does the same. The Inbox surfaces questions alongside +its usual checkpoint answers. From a terminal: + +```bash +openspec-ui-cli answer --question "Which branch strategy?" --answer "gitflow" +``` + +## What this changes about autonomy + +Before this, an autonomy level of `full` meant the chain ran without +interruption. Now, a question is a hard stop regardless of autonomy level. +The chain waits for a human answer, even at full autonomy. This is +intentional: a question from an agent is a request for judgment, not a +checkpoint the chain can resolve on its own. + +The refusal of a run past an open question is explicit. If someone tries +to start a new agent run on a change that still has unanswered questions, +the product says so and names the open questions. This prevents a second +agent from running while the first is still waiting for an answer. + +## Try it + +The code is at +[github.com/VeryComplexAndLongName/OpenSpec-UI](https://github.com/VeryComplexAndLongName/OpenSpec-UI), +where the repository and packages keep the name OpenSpec-UI. + +```bash +openspec-ui-cli answer --question --answer +``` diff --git a/docs/articles/devto/2026-10-30-every-message-has-an-identifier-from-one-register.md b/docs/articles/devto/2026-10-30-every-message-has-an-identifier-from-one-register.md new file mode 100644 index 00000000..24efd5c0 --- /dev/null +++ b/docs/articles/devto/2026-10-30-every-message-has-an-identifier-from-one-register.md @@ -0,0 +1,63 @@ +--- +title: Every message has an identifier, from one register +published: false +description: What the product says to a person is now written in one register, every message carries an OSW-XXX code, and a generated page lets you look up the identifier you saw. +tags: openspec, devtools, typescript, opensource +cover_image: https://raw.githubusercontent.com/VeryComplexAndLongName/OpenSpec-UI/main/docs/articles/site/every-message-has-an-identifier-from-one-register/cover.jpg +canonical_url: https://openspec-ui.dev/articles/every-message-has-an-identifier-from-one-register/ +--- + +*First published on [openspec-ui.dev](https://openspec-ui.dev/articles/every-message-has-an-identifier-from-one-register/).* + +What the product says to a person — a failure's reason, a refusal, a CLI +error — was written where it is said, as a sentence. A person cannot look +up a message they saw, a host cannot act on one except by reading its +words, and nothing says which messages exist. A new register decides that +every message is said as ` OSW--: `, from one +place, and that the register comes first with the groups `CLI`, `RUN`, +`QST` and `PRM`. + +## The register, and what it holds + +`message-register.ts` in core holds the 14 groups, every message's +identifier, level, words with named values, why it is said and what to +do. `say`, `formatMessage`, `withMessageCode`, `messageEntryUrl` are the +functions the rest of the product calls. + +The `CLI`, `RUN`, `QST` and `PRM` messages are said from the register: +the CLI's argument errors, the chain's refusals, limits and endings, the +operator's questions, and the permission requests nobody can answer. Their +words do not change; the CLI's lines lose `openspec-ui-cli:` and gain the +form, `error OSW-CLI-003: --cwd requires a value`. + +## A page you can search for + +`docs/messages.md` is generated from the register: a page a person +searches for the identifier they saw. If you see `error OSW-RUN-042` in +your terminal or panel, you can look up what it means, why it was said, +and what to do about it, without guessing from the words alone. + +## Codes on events and in JSON + +`progress`, `failed` and `cancelled` events carry `code` beside their +words, and so does the CLI's JSON. The CLI, the output channel and the +panels put the identifier before the words; the panels show it as a label +that links to its entry. + +## Tests that hold the line + +Tests check that identifiers are well formed and in a group, that every +identifier ever given is kept, that the page matches what the register +says, and a ratchet on the messages still said in place — 323 before, 290 +after, and it may only fall. This ratchet prevents new ad-hoc messages +from being added outside the register. + +## Try it + +The code is at +[github.com/VeryComplexAndLongName/OpenSpec-UI](https://github.com/VeryComplexAndLongName/OpenSpec-UI), +where the repository and packages keep the name OpenSpec-UI. + +```bash +openspec-ui-cli run change --cwd . 2>&1 | grep 'OSW-' +``` diff --git a/docs/articles/devto/2026-11-04-a-change-is-committed-where-it-is-made.md b/docs/articles/devto/2026-11-04-a-change-is-committed-where-it-is-made.md new file mode 100644 index 00000000..834ab35e --- /dev/null +++ b/docs/articles/devto/2026-11-04-a-change-is-committed-where-it-is-made.md @@ -0,0 +1,68 @@ +--- +title: A change is committed where it is made +published: false +description: Agent workflow rules now say when to commit and push. A new change is committed and pushed as it is made. A card of a change's own worktree offers Commit Change, and the git stage commits what the stages left. +tags: openspec, git, opensource, productivity +cover_image: https://raw.githubusercontent.com/VeryComplexAndLongName/OpenSpec-UI/main/docs/articles/site/a-change-is-committed-where-it-is-made/cover.jpg +canonical_url: https://openspec-ui.dev/articles/a-change-is-committed-where-it-is-made/ +--- + +*First published on [openspec-ui.dev](https://openspec-ui.dev/articles/a-change-is-committed-where-it-is-made/).* + +A change worked in its own worktree — since ADR 0043 the usual change — +could have its own harness set nowhere but in the file. The Changes tree +drew such a change as one worked "elsewhere" and gave it a shortened menu, +and the Pipeline's card offered only Start, the run's controls and Logs. +Every control added to the tree and not to the card, or the other way +round, left one host or one kind of change poorer. + +The owner decided the same day: when a change is made, everything needed +is done, so the change can be worked at once as one's own. + +## The rules, now with when + +The agent workflow rules say when: commit the planning artifacts on the +change's branch and push it with an upstream as soon as they are written; +commit and push after every task ticked; leave nothing uncommitted or +unpushed at the end of a turn; nothing of a change on `main`; a refused +push is said, not worked around. + +Create Change, in both hosts, commits the new change on its branch and +pushes it at once. A refused push leaves the change made and says why +(`OSW-GIT-203`). + +The `git` stage commits what the stages left before it pushes +(`OSW-GIT-103` where that commit fails). + +## The survey and the card + +The survey says where a change's own branch is not on the server: never +pushed, or at another commit. Read from the refs it lists anyway, so no +git runs in the directory. + +A card of a change's own worktree says so ("not on the server"), and a +new action, **Commit Change**, commits everything the worktree holds on +the change's branch and pushes it. On the card and in Show Actions..., in +both hosts; refused in the main checkout and on the default branch. + +A card of a change's own worktree offers its actions in the arrangement +by step as on the board, and **Run Change...**: the owner found on +2026-10-10 that such a change could be acted on but never run — a card's +Start was refused for a change this checkout does not have. It runs in +the change's worktree, in both hosts. + +## Messages in the new GIT group + +Messages in the register's new GIT group (`OSW-GIT-001`..`203`) name +every failure, refusal and success in the commit and push path. ADR 0043 +is amended to reflect the new rules. + +## Try it + +The code is at +[github.com/VeryComplexAndLongName/OpenSpec-UI](https://github.com/VeryComplexAndLongName/OpenSpec-UI), +where the repository and packages keep the name OpenSpec-UI. + +```bash +openspec-ui-cli commit change --cwd . +``` diff --git a/docs/articles/devto/2026-11-09-a-change-runs-in-its-own-worktree.md b/docs/articles/devto/2026-11-09-a-change-runs-in-its-own-worktree.md new file mode 100644 index 00000000..2507e5f8 --- /dev/null +++ b/docs/articles/devto/2026-11-09-a-change-runs-in-its-own-worktree.md @@ -0,0 +1,65 @@ +--- +title: A change runs in its own worktree +published: false +description: A run inside one of the repository's worktrees is given that worktree's own agents, whose sandbox is that worktree. Any other run gets the workspace's, whose sandbox still refuses a directory that is neither. +tags: openspec, devtools, vscode, opensource +cover_image: https://raw.githubusercontent.com/VeryComplexAndLongName/OpenSpec-UI/main/docs/articles/site/a-change-runs-in-its-own-worktree/cover.jpg +canonical_url: https://openspec-ui.dev/articles/a-change-runs-in-its-own-worktree/ +--- + +*First published on [openspec-ui.dev](https://openspec-ui.dev/articles/a-change-runs-in-its-own-worktree/).* + +The owner ran a change of `HppMCP` from its card, where a-change-is-committed-where-it-is-made +had just put Run Change...: + +> stage started: apply (local-llm-acp) +> failed: cwd "C:/Prog/.worktrees/HppMCP/mcp-platform-foundation" is outside the workspace "c:\Prog\HppMCP" + +A host binds its agents to one root, its workspace, and every agent's +sandbox refuses a run whose `cwd` is outside it. A change is made in a +worktree of its own (ADR 0043), under `//`, +which is not inside the workspace. The chain, a single stage, and a card's +controls of a run all resolved their agent by its id alone, so every run +in a worktree was refused — in the editor and in the standalone app alike. + +The CLI never met it: `openspec-ui-cli run change --cwd` builds its agents +for that directory. The run dialog's answers had the same blind spot: +applying a named configuration wrote the checkout's copy of the change's +`harness.json`, not the worktree's. + +## Worktree-specific agents + +A run inside one of the repository's worktrees is given that worktree's +own agents, made once per worktree, whose sandbox is that worktree. Any +other run gets the workspace's, whose sandbox still refuses a directory +that is neither. `runRootOf` and `agentsByRunRoot` in core decide it. + +The chain runner asks for its agent with the stage's `cwd`; the editor's +AI panel, its card controls and the standalone server's chain and socket +runs do the same. + +## The run dialog, fixed + +The run dialog's answers in the editor read and write the change's +harness where the change is worked. Before this, applying a named +configuration wrote the checkout's copy of the change's `harness.json`, +not the worktree's. Now it writes the worktree's copy, and reads it back +from the same place. + +## What this changes about the workflow + +Before this, a change in its own worktree could be acted on but never run +from its card. The card's Start was refused for a change this checkout +does not have. Now it runs in the change's worktree, in both hosts. The +card offers Run Change... alongside its other actions, and the action +runs where the change is worked. + +## Try it + +The code is at +[github.com/VeryComplexAndLongName/OpenSpec-UI](https://github.com/VeryComplexAndLongName/OpenSpec-UI), +where the repository and packages keep the name OpenSpec-UI. + +```bash +openspec-ui-cli run change --cwd C:/Prog/.worktrees/HppMCP/mcp-platform-foundation +``` diff --git a/docs/articles/linkedin/2026-10-18-a-compliance-monitor-that-does-not-busywork.md b/docs/articles/linkedin/2026-10-18-a-compliance-monitor-that-does-not-busywork.md new file mode 100644 index 00000000..cca45bd4 --- /dev/null +++ b/docs/articles/linkedin/2026-10-18-a-compliance-monitor-that-does-not-busywork.md @@ -0,0 +1,32 @@ +# LinkedIn post: a-compliance-monitor-that-does-not-busywork + +Publish between 2026-10-18 and 2026-10-20: the site page is live from 2026-10-15, +and this goes out three to five days after it, not on the same day. +Attach: `docs/articles/site/a-compliance-monitor-that-does-not-busywork/cover.jpg`. +Put the repository link in the first comment, not in the post. + +## Post + +OpenSpec Workbench initializes repositories and runs agents on changes. It +did not, until now, check that its own runtime files are ignored, or that its +repository rules are consistent. + +A compliance monitor has been added to the shared core. Three things matter: +it keeps a versioned catalogue of rules, it runs only when the host reports +idle, and it reports findings without moving or deleting anything. + +Each rule accepts `autorepair`, `advice` or `none`. The monitor runs one +bounded batch only after the host reports idle and no mutating run is active. + +A companion capability, the process ledger, records a snapshot for every +spawned process and flags orphans as read-only findings. Compliance explains; +recovery acts. + +Full write-up: https://openspec-ui.dev/articles/a-compliance-monitor-that-does-not-busywork/ + +Have you had a tool that checked its own housekeeping? + +## First comment + +The code, the issues and the extension: https://github.com/VeryComplexAndLongName/OpenSpec-UI +(The product is OpenSpec Workbench. The repository and packages are still called OpenSpec-UI.) diff --git a/docs/articles/linkedin/2026-10-23-local-models-can-now-search-the-web-and-fetch-pages.md b/docs/articles/linkedin/2026-10-23-local-models-can-now-search-the-web-and-fetch-pages.md new file mode 100644 index 00000000..3e0f1381 --- /dev/null +++ b/docs/articles/linkedin/2026-10-23-local-models-can-now-search-the-web-and-fetch-pages.md @@ -0,0 +1,28 @@ +# LinkedIn post: local-models-can-now-search-the-web-and-fetch-pages + +Publish between 2026-10-23 and 2026-10-25: the site page is live from 2026-10-20, +and this goes out three to five days after it, not on the same day. +Attach: `docs/articles/site/local-models-can-now-search-the-web-and-fetch-pages/cover.jpg`. +Put the repository link in the first comment, not in the post. + +## Post + +A local model is only as useful as the information it can bring to bear. +Until this week, a local agent could reason about what was already in its +context window, but it could not look up a current fact or read a source page. + +Two new shared core tools: `search_web` and `fetch_webpage`. They let +local-model agents consult a SearXNG endpoint and retrieve HTML pages as +Markdown-backed JSON artifacts - clean content, tables preserved, remote +content treated as untrusted data. + +Both local-model adapters get the tools. Remote agents are unchanged. + +Full write-up: https://openspec-ui.dev/articles/local-models-can-now-search-the-web-and-fetch-pages/ + +What is the one thing your local model cannot do that would make it actually useful? + +## First comment + +The code, the issues and the extension: https://github.com/VeryComplexAndLongName/OpenSpec-UI +(The product is OpenSpec Workbench. The repository and packages are still called OpenSpec-UI.) diff --git a/docs/articles/linkedin/2026-10-28-the-agent-asks-the-operator-and-the-chain-waits.md b/docs/articles/linkedin/2026-10-28-the-agent-asks-the-operator-and-the-chain-waits.md new file mode 100644 index 00000000..b86cf2ff --- /dev/null +++ b/docs/articles/linkedin/2026-10-28-the-agent-asks-the-operator-and-the-chain-waits.md @@ -0,0 +1,28 @@ +# LinkedIn post: the-agent-asks-the-operator-and-the-chain-waits + +Publish between 2026-10-28 and 2026-10-30: the site page is live from 2026-10-25, +and this goes out three to five days after it, not on the same day. +Attach: `docs/articles/site/the-agent-asks-the-operator-and-the-chain-waits/cover.jpg`. +Put the repository link in the first comment, not in the post. + +## Post + +An agent ended its run with four decisions it needed from the operator, and +the product offered no way to answer them. A chain would have gone on to the +next stage with them open. + +The fix: questions are caught, the run stops and waits, nothing goes on +without an answer. Answers are kept in the change's `decisions.md` and in the +audit log, and a question is a hard stop regardless of autonomy level. + +Questions are answered from the card, the AI panel, the Human-Only Inbox and +the CLI. + +Full write-up: https://openspec-ui.dev/articles/the-agent-asks-the-operator-and-the-chain-waits/ + +Have you had an agent ask a question that nobody could answer? + +## First comment + +The code, the issues and the extension: https://github.com/VeryComplexAndLongName/OpenSpec-UI +(The product is OpenSpec Workbench. The repository and packages are still called OpenSpec-UI.) diff --git a/docs/articles/linkedin/2026-11-02-every-message-has-an-identifier-from-one-register.md b/docs/articles/linkedin/2026-11-02-every-message-has-an-identifier-from-one-register.md new file mode 100644 index 00000000..186bb785 --- /dev/null +++ b/docs/articles/linkedin/2026-11-02-every-message-has-an-identifier-from-one-register.md @@ -0,0 +1,28 @@ +# LinkedIn post: every-message-has-an-identifier-from-one-register + +Publish between 2026-11-02 and 2026-11-04: the site page is live from 2026-10-30, +and this goes out three to five days after it, not on the same day. +Attach: `docs/articles/site/every-message-has-an-identifier-from-one-register/cover.jpg`. +Put the repository link in the first comment, not in the post. + +## Post + +What the product says to a person - a failure's reason, a refusal, a CLI +error - was written where it is said, as a sentence. Nobody could look up a +message they saw. + +A new register says every message as ` OSW--: `, +from one place. `docs/messages.md` is generated from it: search for the code +you saw and find what it means, why it was said, and what to do. + +Events and the CLI's JSON carry `code` beside the words. The words themselves +do not change - the goal is traceability, not rewriting. + +Full write-up: https://openspec-ui.dev/articles/every-message-has-an-identifier-from-one-register/ + +What is the one error message you wish you could look up by code? + +## First comment + +The code, the issues and the extension: https://github.com/VeryComplexAndLongName/OpenSpec-UI +(The product is OpenSpec Workbench. The repository and packages are still called OpenSpec-UI.) diff --git a/docs/articles/linkedin/2026-11-07-a-change-is-committed-where-it-is-made.md b/docs/articles/linkedin/2026-11-07-a-change-is-committed-where-it-is-made.md new file mode 100644 index 00000000..14a43cee --- /dev/null +++ b/docs/articles/linkedin/2026-11-07-a-change-is-committed-where-it-is-made.md @@ -0,0 +1,29 @@ +# LinkedIn post: a-change-is-committed-where-it-is-made + +Publish between 2026-11-07 and 2026-11-09: the site page is live from 2026-11-04, +and this goes out three to five days after it, not on the same day. +Attach: `docs/articles/site/a-change-is-committed-where-it-is-made/cover.jpg`. +Put the repository link in the first comment, not in the post. + +## Post + +A change worked in its own worktree could have its own harness set nowhere but +in the file. Every control added to the tree and not to the card, or the other +way round, left one host or one kind of change poorer. + +The fix: when a change is made, everything needed is done. The agent rules now +say when - commit the planning artifacts on the change's branch and push it as +soon as they are written; commit and push after every task ticked; leave +nothing uncommitted at the end of a turn. + +Create Change commits and pushes the new change at once. A card offers Commit +Change and Run Change in the arrangement by step, not just on the board. + +Full write-up: https://openspec-ui.dev/articles/a-change-is-committed-where-it-is-made/ + +If you have ever lost work because a tool forgot to commit, what did you do about it? + +## First comment + +The code, the issues and the extension: https://github.com/VeryComplexAndLongName/OpenSpec-UI +(The product is OpenSpec Workbench. The repository and packages are still called OpenSpec-UI.) diff --git a/docs/articles/linkedin/2026-11-12-a-change-runs-in-its-own-worktree.md b/docs/articles/linkedin/2026-11-12-a-change-runs-in-its-own-worktree.md new file mode 100644 index 00000000..e2776e6e --- /dev/null +++ b/docs/articles/linkedin/2026-11-12-a-change-runs-in-its-own-worktree.md @@ -0,0 +1,31 @@ +# LinkedIn post: a-change-runs-in-its-own-worktree + +Publish between 2026-11-12 and 2026-11-14: the site page is live from 2026-11-09, +and this goes out three to five days after it, not on the same day. +Attach: `docs/articles/site/a-change-runs-in-its-own-worktree/cover.jpg`. +Put the repository link in the first comment, not in the post. + +## Post + +The owner ran a change from its card, and the stage failed: cwd is outside +the workspace. + +A host binds its agents to one root, and every agent's sandbox refuses a run +whose cwd is outside it. A change is made in a worktree of its own, which is +not inside the workspace - so every run in a worktree was refused. + +The fix: a run inside a worktree gets that worktree's own agents, whose +sandbox is that worktree. The run dialog reads and writes the change's harness +where the change is worked. + +The CLI never met this problem - it always built its agents for the directory +you pointed at. + +Full write-up: https://openspec-ui.dev/articles/a-change-runs-in-its-own-worktree/ + +Have you had a sandbox that was too strict for its own good? + +## First comment + +The code, the issues and the extension: https://github.com/VeryComplexAndLongName/OpenSpec-UI +(The product is OpenSpec Workbench. The repository and packages are still called OpenSpec-UI.) diff --git a/docs/articles/site/2026-10-15-a-compliance-monitor-that-does-not-busywork.md b/docs/articles/site/2026-10-15-a-compliance-monitor-that-does-not-busywork.md new file mode 100644 index 00000000..a8d570bd --- /dev/null +++ b/docs/articles/site/2026-10-15-a-compliance-monitor-that-does-not-busywork.md @@ -0,0 +1,95 @@ +--- +title: A compliance monitor that does not busywork +summary: OpenSpec Workbench now ships a versioned catalogue of rules, checks that run only when the host is idle, and findings that explain what is wrong without moving a single file. +cover: cover.jpg +cover_alt: The OpenSpec Workbench owl, alert, beside the words A compliance monitor that does not busywork +--- + +OpenSpec Workbench initializes repositories and runs agents on changes. It +did not, until now, check that its own runtime files are ignored, or that its +repository rules are consistent. A compliance monitor has been added to the +shared core, and it does three things that matter: it keeps a versioned +catalogue of rules, it runs only when the host reports idle, and it reports +findings without moving or deleting anything. + +## The catalogue, versioned and evidence-linked + +Every rule in the catalogue carries a stable identifier, a description of +what it checks, and metadata about the check's cost and whether it supports +automatic repair. Each finding is linked back to the rule that produced it +and to the evidence that triggered it, so a person can trace a finding to +the exact check and the exact file or state that caused it. + +The catalogue is versioned. When a rule changes, the new version is applied +to future checks, and old findings remain linked to the version that +produced them. This matters when a rule's threshold is tightened or +relaxed: old findings do not retroactively become violations or pass. + +## What it checks, on initialization + +On explicit repository initialization, the monitor verifies that Workbench +runtime state is ignored by Git. It adds only the missing managed ignore +rule, preserving the rest of `.gitignore` exactly as the user wrote it. +Nothing is overwritten. + +It also checks Workbench runtime files in the main checkout and in +worktrees. It identifies untracked or visible state and explains the +expected root for each state kind without moving or deleting it. A run +journal in `.openspec-ui/` is expected to be untracked; a lease file in the +main checkout is expected to be ignored. The monitor says which is which, +and why. + +## Grouping, deduplication and shadow detection + +When the same change id appears in multiple worktrees, the monitor groups +them as one logical change and reports the count. It flags a change id +present in both active and archive trees, an archived change left in a +stale worktree, or a shadow copy in main beside its owning worktree. The +Pipeline card count is reconciled with the Changes list, and active changes +missing from the OpenSpec README index are flagged with a suggested link, +not an automatic edit. + +## Per-rule reactions and a periodic schedule + +Each rule accepts one of three response settings: `autorepair`, `advice` +or `none`. `autorepair` applies a fix without asking; `advice` produces a +finding with a suggested action; `none` records the finding silently. A +global periodic-monitor switch enables or disables the entire schedule. + +The monitor runs one bounded batch only after the host reports idle and no +mutating Workbench run is active. It measures each check's elapsed time, +schedules by due date and conservative cost, and spreads expensive checks +across later idle windows. Nothing runs as a separate OS daemon. + +## Process ledger and orphan detection + +A companion capability, the process ledger, records a synchronous snapshot +for every process spawned by Workbench: PID, OS start time, executable, +hostname, cwd, change, and a secret-free command-line hash. Records are +marked exited on normal close and kept durable across host restarts, keyed +by canonical repository identity and hostname. + +Before any kill, the snapshot is re-verified against the operating system. +Orphaned and overdue processes are surfaced as read-only Compliance +findings. An explicit, confirmable kill lives in the existing recovery +surface, never in Compliance itself. The two capabilities share the same +catalogue but never cross their boundaries: Compliance explains, recovery +acts. + +## What this deliberately does not do + +The monitor does not start a background daemon, does not modify source code, +does not run on every file change, and does not replace a linter or a +formatter. It checks Workbench's own runtime hygiene and the consistency of +its repository state. A paid plugin, if one ever comes, would build on the +facts this records and change none of them. + +## Try it + +The code is at +[github.com/VeryComplexAndLongName/OpenSpec-UI](https://github.com/VeryComplexAndLongName/OpenSpec-UI), +where the repository and packages keep the name OpenSpec-UI. + +```bash +openspec-ui-cli compliance check --cwd . +``` diff --git a/docs/articles/site/2026-10-20-local-models-can-now-search-the-web-and-fetch-pages.md b/docs/articles/site/2026-10-20-local-models-can-now-search-the-web-and-fetch-pages.md new file mode 100644 index 00000000..c04b6cce --- /dev/null +++ b/docs/articles/site/2026-10-20-local-models-can-now-search-the-web-and-fetch-pages.md @@ -0,0 +1,71 @@ +--- +title: Local models can now search the web and fetch pages +summary: Two new shared core tools, search_web and fetch_webpage, let local-model agents consult a SearXNG endpoint and retrieve HTML pages as Markdown. No remote agents are changed. +cover: cover.jpg +cover_alt: The OpenSpec Workbench owl, reading, beside the words Local models can now search the web and fetch pages +--- + +OpenSpec Workbench puts local-model behavior and its security controls in +the shared core, but until now neither local adapter could search the web +or fetch a source page. Two new shared core tools have been added: +`search_web` and `fetch_webpage`. They let local-model agents consult a +SearXNG endpoint and retrieve HTML pages as Markdown-backed JSON artifacts +that can be analyzed or passed to another agent. + +## What the tools do + +`search_web` sends a query to a SearXNG JSON endpoint and returns the +results as structured data. `fetch_webpage` retrieves a public HTTP(S) URL, +converts the article or main content to Markdown, writes every data table +as a Markdown table, and returns provenance, page metadata and timestamps +in JSON. + +Both tools are available to both local-model adapters: `local-llm` and +`local-llm-acp`. Remote agents are unchanged. The tools do not speak to +any vendor API; they speak only to the SearXNG instance you configure. + +## Configuration and bounds + +The single SearXNG instance is configured with the `OPENSPEC_UI_SEARXNG_URL` +environment variable. When search has not been configured, the tools return +an explicit error rather than failing silently or hanging. + +Page fetching is restricted to bounded public HTTP(S) HTML. Pages larger +than the configured bound are read up to the bound and the response says +so. Remote content is treated as untrusted data throughout the pipeline. + +## Why this matters for local models + +A local model is only as useful as the information it can bring to bear. +Before these tools, a local agent could reason about what was already in +its context window, but it could not look up a current fact or read a +source page. Now it can search for context and fetch the page that +contains it, all without sending data to a remote API. + +The tools return Markdown-backed JSON artifacts, not raw HTML. This means +the local model receives clean, structured content that fits into its +context window more efficiently, and that data tables are preserved as +Markdown tables rather than lost in markup noise. + +## What this deliberately does not do + +These tools are not a general-purpose web browser. They do not execute +JavaScript, they do not render CSS, and they do not interact with forms +or buttons. They search and fetch, convert to Markdown, and return. If a +page requires JavaScript to render its content, the fetch will return +whatever the server sends without execution. + +They also do not change the command or event protocol. No new transport +channels are opened, no new agent types are introduced. The tools are +exposed through the existing local-model adapters, and the environment +configuration is read by the shared core runner. + +## Try it + +The code is at +[github.com/VeryComplexAndLongName/OpenSpec-UI](https://github.com/VeryComplexAndLongName/OpenSpec-UI), +where the repository and packages keep the name OpenSpec-UI. + +```bash +OPENSPEC_UI_SEARXNG_URL=http://localhost:8080 openspec-ui-cli run --change my-change +``` diff --git a/docs/articles/site/2026-10-25-the-agent-asks-the-operator-and-the-chain-waits.md b/docs/articles/site/2026-10-25-the-agent-asks-the-operator-and-the-chain-waits.md new file mode 100644 index 00000000..b2a00d6a --- /dev/null +++ b/docs/articles/site/2026-10-25-the-agent-asks-the-operator-and-the-chain-waits.md @@ -0,0 +1,76 @@ +--- +title: The agent asks the operator, and the chain waits +summary: An agent can now raise a question for the operator, the chain stops and waits, answers are kept in decisions.md, and the product's own agent asks in its turn from the start. +cover: cover.jpg +cover_alt: The OpenSpec Workbench owl, listening, beside the words The agent asks the operator, and the chain waits +--- + +An agent ended its run with four decisions it needed from the operator, +and the product offered no way to answer them. A chain would have gone on +to the next stage with them open. The owner decided the same day: questions +are caught, the run stops and waits, nothing goes on without an answer, the +answers are kept in the change's `decisions.md` and in the audit log, and +the product's own agent asks in its turn from the start. + +## The marker, the event and the command + +Every agent stage's instruction asks for `Question for the operator: <…>` +lines for decisions the agent needs. The product reads them as markers. +`local-llm-acp` gets an `ask_operator` tool that blocks its turn until +answered. + +A `question` event and an `answerQuestion` command are added to the +protocol. A `question` waiting kind appears in the run's status. A run +that asked waits instead of completing, in a chain or alone, under every +autonomy level. Once answered, the stage runs again with the answers — +`update` for propose and review, the same command otherwise. + +## Where answers live + +`openspec/changes//decisions.md` holds every question and answer. +The audit log records both. An agent run on a change with an open question +is refused. + +Questions are answered from the card, the AI panel, the Human-Only Inbox +and `openspec-ui-cli answer`. The card shows open questions with answer +fields; the panel does the same. The Inbox surfaces questions alongside +its usual checkpoint answers. From a terminal: + +```bash +openspec-ui-cli answer --question "Which branch strategy?" --answer "gitflow" +``` + +## What this changes about autonomy + +Before this, an autonomy level of `full` meant the chain ran without +interruption. Now, a question is a hard stop regardless of autonomy level. +The chain waits for a human answer, even at full autonomy. This is +intentional: a question from an agent is a request for judgment, not a +checkpoint the chain can resolve on its own. + +The refusal of a run past an open question is explicit. If someone tries +to start a new agent run on a change that still has unanswered questions, +the product says so and names the open questions. This prevents a second +agent from running while the first is still waiting for an answer. + +## What this deliberately does not do + +The product does not auto-answer questions. It does not infer an answer +from context, from the change's proposal, or from any other signal. A +question is a question until answered. It does not time out. It does not +escalate. It waits. + +The `ask_operator` tool is only available to `local-llm-acp`. Other ACP +adapters do not have it yet. If an agent needs to ask a question and its +adapter does not support it, the agent can still raise the marker in its +output text, and the product will catch it. + +## Try it + +The code is at +[github.com/VeryComplexAndLongName/OpenSpec-UI](https://github.com/VeryComplexAndLongName/OpenSpec-UI), +where the repository and packages keep the name OpenSpec-UI. + +```bash +openspec-ui-cli answer --question --answer +``` diff --git a/docs/articles/site/2026-10-30-every-message-has-an-identifier-from-one-register.md b/docs/articles/site/2026-10-30-every-message-has-an-identifier-from-one-register.md new file mode 100644 index 00000000..fed26835 --- /dev/null +++ b/docs/articles/site/2026-10-30-every-message-has-an-identifier-from-one-register.md @@ -0,0 +1,70 @@ +--- +title: Every message has an identifier, from one register +summary: What the product says to a person is now written in one register, every message carries an OSW-XXX code, and a generated page lets you look up the identifier you saw. +cover: cover.jpg +cover_alt: The OpenSpec Workbench owl, reading, beside the words Every message has an identifier, from one register +--- + +What the product says to a person — a failure's reason, a refusal, a CLI +error — was written where it is said, as a sentence. A person cannot look +up a message they saw, a host cannot act on one except by reading its +words, and nothing says which messages exist. A new register decides that +every message is said as ` OSW--: `, from one +place, and that the register comes first with the groups `CLI`, `RUN`, +`QST` and `PRM`. + +## The register, and what it holds + +`message-register.ts` in core holds the 14 groups, every message's +identifier, level, words with named values, why it is said and what to +do. `say`, `formatMessage`, `withMessageCode`, `messageEntryUrl` are the +functions the rest of the product calls. + +The `CLI`, `RUN`, `QST` and `PRM` messages are said from the register: +the CLI's argument errors, the chain's refusals, limits and endings, the +operator's questions, and the permission requests nobody can answer. Their +words do not change; the CLI's lines lose `openspec-ui-cli:` and gain the +form, `error OSW-CLI-003: --cwd requires a value`. + +## A page you can search for + +`docs/messages.md` is generated from the register: a page a person +searches for the identifier they saw. If you see `error OSW-RUN-042` in +your terminal or panel, you can look up what it means, why it was said, +and what to do about it, without guessing from the words alone. + +## Codes on events and in JSON + +`progress`, `failed` and `cancelled` events carry `code` beside their +words, and so does the CLI's JSON. The CLI, the output channel and the +panels put the identifier before the words; the panels show it as a label +that links to its entry. + +## Tests that hold the line + +Tests check that identifiers are well formed and in a group, that every +identifier ever given is kept, that the page matches what the register +says, and a ratchet on the messages still said in place — 323 before, 290 +after, and it may only fall. This ratchet prevents new ad-hoc messages +from being added outside the register. + +## What this deliberately does not do + +The product does not change the words of existing messages. What changes +is where they are said and how they are formatted. The CLI's lines lose +their prefix and gain the new form, but the message text itself is +unchanged. This is intentional: the goal is traceability, not rewriting. + +The register does not cover every message in the product. Some messages +are still said in place, outside the register. The ratchet counts them +and ensures the number only falls over time. + +## Try it + +The code is at +[github.com/VeryComplexAndLongName/OpenSpec-UI](https://github.com/VeryComplexAndLongName/OpenSpec-UI), +where the repository and packages keep the name OpenSpec-UI. + +```bash +openspec-ui-cli run change --cwd . 2>&1 | grep 'OSW-' +``` diff --git a/docs/articles/site/2026-11-04-a-change-is-committed-where-it-is-made.md b/docs/articles/site/2026-11-04-a-change-is-committed-where-it-is-made.md new file mode 100644 index 00000000..d82188c9 --- /dev/null +++ b/docs/articles/site/2026-11-04-a-change-is-committed-where-it-is-made.md @@ -0,0 +1,76 @@ +--- +title: A change is committed where it is made +summary: Agent workflow rules now say when to commit and push. A new change is committed and pushed as it is made. A card of a change's own worktree offers Commit Change, and the git stage commits what the stages left. +cover: cover.jpg +cover_alt: The OpenSpec Workbench owl, pushing, beside the words A change is committed where it is made +--- + +A change worked in its own worktree — since ADR 0043 the usual change — +could have its own harness set nowhere but in the file. The Changes tree +drew such a change as one worked "elsewhere" and gave it a shortened menu, +and the Pipeline's card offered only Start, the run's controls and Logs. +Every control added to the tree and not to the card, or the other way +round, left one host or one kind of change poorer. + +The owner decided the same day: when a change is made, everything needed +is done, so the change can be worked at once as one's own. + +## The rules, now with when + +The agent workflow rules say when: commit the planning artifacts on the +change's branch and push it with an upstream as soon as they are written; +commit and push after every task ticked; leave nothing uncommitted or +unpushed at the end of a turn; nothing of a change on `main`; a refused +push is said, not worked around. + +Create Change, in both hosts, commits the new change on its branch and +pushes it at once. A refused push leaves the change made and says why +(`OSW-GIT-203`). + +The `git` stage commits what the stages left before it pushes +(`OSW-GIT-103` where that commit fails). + +## The survey and the card + +The survey says where a change's own branch is not on the server: never +pushed, or at another commit. Read from the refs it lists anyway, so no +git runs in the directory. + +A card of a change's own worktree says so ("not on the server"), and a +new action, **Commit Change**, commits everything the worktree holds on +the change's branch and pushes it. On the card and in Show Actions..., in +both hosts; refused in the main checkout and on the default branch. + +A card of a change's own worktree offers its actions in the arrangement +by step as on the board, and **Run Change...**: the owner found on +2026-10-10 that such a change could be acted on but never run — a card's +Start was refused for a change this checkout does not have. It runs in +the change's worktree, in both hosts. + +## Messages in the new GIT group + +Messages in the register's new GIT group (`OSW-GIT-001`..`203`) name +every failure, refusal and success in the commit and push path. ADR 0043 +is amended to reflect the new rules. + +## What this deliberately does not do + +The product does not auto-merge. It does not open pull requests on your +behalf. It commits and pushes; the merge gate, the archive pass and the +forge integration handle the rest. A refused push is said, not worked +around, and the change is left in a state where you can decide what to do +next. + +The Commit Change action is refused in the main checkout and on the +default branch. It only works on a change's own worktree, where the +change's branch is the current one. + +## Try it + +The code is at +[github.com/VeryComplexAndLongName/OpenSpec-UI](https://github.com/VeryComplexAndLongName/OpenSpec-UI), +where the repository and packages keep the name OpenSpec-UI. + +```bash +openspec-ui-cli commit change --cwd . +``` diff --git a/docs/articles/site/2026-11-09-a-change-runs-in-its-own-worktree.md b/docs/articles/site/2026-11-09-a-change-runs-in-its-own-worktree.md new file mode 100644 index 00000000..9552a85d --- /dev/null +++ b/docs/articles/site/2026-11-09-a-change-runs-in-its-own-worktree.md @@ -0,0 +1,73 @@ +--- +title: A change runs in its own worktree +summary: A run inside one of the repository's worktrees is given that worktree's own agents, whose sandbox is that worktree. Any other run gets the workspace's, whose sandbox still refuses a directory that is neither. +cover: cover.jpg +cover_alt: The OpenSpec Workbench owl, working in its own space, beside the words A change runs in its own worktree +--- + +The owner ran a change of `HppMCP` from its card, where a-change-is-committed-where-it-is-made +had just put Run Change...: + +> stage started: apply (local-llm-acp) +> failed: cwd "C:/Prog/.worktrees/HppMCP/mcp-platform-foundation" is outside the workspace "c:\Prog\HppMCP" + +A host binds its agents to one root, its workspace, and every agent's +sandbox refuses a run whose `cwd` is outside it. A change is made in a +worktree of its own (ADR 0043), under `//`, +which is not inside the workspace. The chain, a single stage, and a card's +controls of a run all resolved their agent by its id alone, so every run +in a worktree was refused — in the editor and in the standalone app alike. + +The CLI never met it: `openspec-ui-cli run change --cwd` builds its agents +for that directory. The run dialog's answers had the same blind spot: +applying a named configuration wrote the checkout's copy of the change's +`harness.json`, not the worktree's. + +## Worktree-specific agents + +A run inside one of the repository's worktrees is given that worktree's +own agents, made once per worktree, whose sandbox is that worktree. Any +other run gets the workspace's, whose sandbox still refuses a directory +that is neither. `runRootOf` and `agentsByRunRoot` in core decide it. + +The chain runner asks for its agent with the stage's `cwd`; the editor's +AI panel, its card controls and the standalone server's chain and socket +runs do the same. + +## The run dialog, fixed + +The run dialog's answers in the editor read and write the change's +harness where the change is worked. Before this, applying a named +configuration wrote the checkout's copy of the change's `harness.json`, +not the worktree's. Now it writes the worktree's copy, and reads it back +from the same place. + +## What this changes about the workflow + +Before this, a change in its own worktree could be acted on but never run +from its card. The card's Start was refused for a change this checkout +does not have. Now it runs in the change's worktree, in both hosts. The +card offers Run Change... alongside its other actions, and the action +runs where the change is worked. + +## What this deliberately does not do + +The product does not change the workspace binding. Each host still binds +its agents to one root. What changes is that a worktree gets its own +agents, and those agents' sandbox is the worktree, not the workspace. +This is a small change with a big effect: it lets a change run where it +lives, without moving the change or the workspace. + +The CLI never met this problem. `openspec-ui-cli run change --cwd` builds +its agents for that directory, so it always worked from the terminal. This +fix was only needed for the editor and the standalone app. + +## Try it + +The code is at +[github.com/VeryComplexAndLongName/OpenSpec-UI](https://github.com/VeryComplexAndLongName/OpenSpec-UI), +where the repository and packages keep the name OpenSpec-UI. + +```bash +openspec-ui-cli run change --cwd C:/Prog/.worktrees/HppMCP/mcp-platform-foundation +``` diff --git a/docs/articles/site/a-change-is-committed-where-it-is-made/cover.jpg b/docs/articles/site/a-change-is-committed-where-it-is-made/cover.jpg new file mode 100644 index 00000000..52772274 Binary files /dev/null and b/docs/articles/site/a-change-is-committed-where-it-is-made/cover.jpg differ diff --git a/docs/articles/site/a-change-runs-in-its-own-worktree/cover.jpg b/docs/articles/site/a-change-runs-in-its-own-worktree/cover.jpg new file mode 100644 index 00000000..cdd22dec Binary files /dev/null and b/docs/articles/site/a-change-runs-in-its-own-worktree/cover.jpg differ diff --git a/docs/articles/site/a-compliance-monitor-that-does-not-busywork/cover.jpg b/docs/articles/site/a-compliance-monitor-that-does-not-busywork/cover.jpg new file mode 100644 index 00000000..27ba2635 Binary files /dev/null and b/docs/articles/site/a-compliance-monitor-that-does-not-busywork/cover.jpg differ diff --git a/docs/articles/site/every-message-has-an-identifier-from-one-register/cover.jpg b/docs/articles/site/every-message-has-an-identifier-from-one-register/cover.jpg new file mode 100644 index 00000000..b2d0d34c Binary files /dev/null and b/docs/articles/site/every-message-has-an-identifier-from-one-register/cover.jpg differ diff --git a/docs/articles/site/local-models-can-now-search-the-web-and-fetch-pages/cover.jpg b/docs/articles/site/local-models-can-now-search-the-web-and-fetch-pages/cover.jpg new file mode 100644 index 00000000..afe59267 Binary files /dev/null and b/docs/articles/site/local-models-can-now-search-the-web-and-fetch-pages/cover.jpg differ diff --git a/docs/articles/site/the-agent-asks-the-operator-and-the-chain-waits/cover.jpg b/docs/articles/site/the-agent-asks-the-operator-and-the-chain-waits/cover.jpg new file mode 100644 index 00000000..70a5fc2a Binary files /dev/null and b/docs/articles/site/the-agent-asks-the-operator-and-the-chain-waits/cover.jpg differ