Skip to content
Open
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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@
All notable changes to OpenLore are documented here. This project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

- **Pi starts with the same lean tool surface as Claude Code.** A Pi session now activates only
the `substrate` tools (the default `openlore install` wires for MCP hosts), plus
`openlore_configure` and the new `openlore_activate_tools`. The activator turns on the `specs`,
`memory`, `review`, `quality`, or `inspect` group, by group name or by any tool name in it. Tool
snippets are one line instead of a repeated description. Set `"pi": { "toolSurface": "all" }` in
`.openlore/config.json` to keep every tool active (#505).
- **Record decisions from the CLI.** `openlore decisions record --title … --rationale …` records the
same draft as the `record_decision` MCP tool, so a repository on the default preset can pass the
decisions gate. The gate and rejection hints no longer name the non-existent
`openlore decisions --record`, and generated agent guidance names the CLI command when the MCP
tool is not wired.

## [3.2.0] - 2026-09-13

**The release where OpenLore checks the locks before reading the map.**
Expand Down
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ For all other cases (reading a file, grepping, listing files) use native tools d
> both tiers; decision c79ec7ca / ADR-0023, superseding ADR-0022). Narrower/wider is opt-in: the lean
> navigate-only `navigation` preset (10 tools, the one-flag escape), `--minimal` (governance core),
> `--preset memory` / `verify` / `federation` / `coordination`, or the full surface via `--preset full`
> (`--all-tools`). The decisions-gate workflow below needs `record_decision`, which is **not** in the
> default — install with `--preset full` (or `--minimal`) on repos that gate commits.
> (`--all-tools`). The `record_decision` MCP tool is **not** in the default; on any preset, record a
> decision for the commit gate with `openlore decisions record --title "…" --rationale "…"`, or
> install with `--preset full` (or `--minimal`) to expose the MCP tool.

> **OpenLore is one substrate with two faces (change `unify-navigation-and-governance-substrate`).**
> Navigation (read the graph) and governance/memory (anchor facts, weigh changes) share one graph, one
Expand Down
10 changes: 10 additions & 0 deletions docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,12 @@ openlore decisions [options]
--json # Machine-readable output
--uninstall-hook # Remove decisions pre-commit hook (install via: openlore setup --tools claude)

# Record a draft decision — the same draft the record_decision MCP tool records, on any wired preset
openlore decisions record --title <text> --rationale <text>
[--consequences <text>] [--files <a.ts,b.ts>] [--supersedes <id>]
[--scope local|component|cross-domain|system] [--constraints-file <path.json>] [--json]
# Prints the draft id and `openlore decisions status <id>` for its verdict

# Decision autopilot (opt-in: { "governance": { "autopilot": true } } in .openlore/config.json):
# the gate auto-accepts verified decisions (distinct `auto-approved` status), syncs them to
# specs with an "Auto-accepted (unreviewed)" marker, and never blocks a commit. Every status
Expand Down Expand Up @@ -744,6 +750,10 @@ field in openlore's `package.json`) and `openlore setup --tools pi --global`
serve daemon, injecting structural context and exposing Pi's curated tool surface.
Pi starts a full-preset backing daemon and curates the model-visible tools itself;
if an existing narrow daemon owns the repository, stop it before starting Pi.
A session starts with the `substrate` tools (the MCP default), `openlore_configure`,
and `openlore_activate_tools`, which turns on the `specs`, `memory`, `review`,
`quality`, or `inspect` group. `"pi": { "toolSurface": "all" }` in
`.openlore/config.json` keeps every tool active.
Its `openlore_prepare_spec_generation` and `openlore_prepare_spec_repair` tools
compose the same deterministic daemon evidence used by MCP hosts; Pi writes or
reconciles the specification itself and OpenLore makes no internal LLM call.
Expand Down
11 changes: 11 additions & 0 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,17 @@ The extension registers the navigation tools (`openlore_orient`, `openlore_searc
caches. Requires Pi ≥ 0.78.1 and one `openlore analyze` beforehand. Full detail in
[`examples/pi/README.md`](../examples/pi/README.md).

A Pi session starts with the same lean tool set Claude Code gets by default (the `substrate`
preset), plus `openlore_configure` and `openlore_activate_tools`. The agent calls
`openlore_activate_tools` to turn on the `specs`, `memory`, `review`, `quality`, or `inspect`
group. To keep every tool active from the start, set:

```json
{ "pi": { "toolSurface": "all" } }
```

in `.openlore/config.json`.

> **What the file contains.** `.pi/extensions/openlore.js` is a four-line re-export shim, not a
> copy of the extension. The shipped extension is plain `tsc` output whose relative imports only
> resolve inside the openlore package, so a copy fails to load. The shim's target path is
Expand Down
12 changes: 8 additions & 4 deletions examples/pi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ fresh while you edit.
- **Context injection** (no tool call needed): each session starts grounded with
the architecture digest (`CODEBASE.md`), the spec-domain index, and a
task-specific `orient` on your first message.
- **Native tools**: the navigation surface as Pi tools —
`openlore_orient`, `openlore_search_code`, `openlore_get_subgraph`,
`openlore_trace_execution_path`, `openlore_analyze_impact`,
`openlore_suggest_insertion_points`, `openlore_get_function_skeleton`.
- **Native tools**: a session starts with the same lean set Claude Code gets
by default (the `substrate` preset) — `openlore_orient`,
`openlore_search_code`, `openlore_get_subgraph`, `openlore_analyze_impact`,
`openlore_recall`, `openlore_verify_claim`, `openlore_blast_radius`, and more.
The agent calls `openlore_activate_tools` to turn on a group when a task needs
it: `specs`, `memory`, `review`, `quality`, or `inspect`. Set
`"pi": { "toolSurface": "all" }` in `.openlore/config.json` to keep every tool
active.
- **Config wizard**: interactive setup on first run, or anytime via `/openlore`
slash command or `openlore_configure` tool.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-09-15
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## Why

A decision can be recorded only through the `record_decision` MCP tool. The default MCP surface
(`substrate`, ADR-0023) does not include that tool, so a collaborator who installs OpenLore with
default settings cannot record a decision, and the pre-commit decisions gate blocks them. The CLI
already tells users to run `openlore decisions --record`, but that option does not exist.

## What Changes

- Add `openlore decisions record`, which records a draft decision with the same behavior as the
`record_decision` MCP tool: the same id, the same "already decided" verdict, anchors, and
background consolidation. Options: `--title`, `--rationale`, `--consequences`, `--files`,
`--supersedes`, `--scope`, `--constraints-file`, `--json`.
- Replace the two messages that name the non-existent `openlore decisions --record` with the new
command.
- When `record_decision` is not in the wired preset, the generated agent guidance names the CLI
command as the way to record a decision, instead of saying that the workflow is unavailable.

## Capabilities

### New Capabilities

None.

### Modified Capabilities

- `cli`: a new requirement for recording decisions from the CLI, and for the gate and guidance
messages that point to it.

## Impact

- `src/cli/commands/decisions.ts`: new `record` subcommand; two message fixes.
- `src/core/analyzer/ai-config-generator.ts`: fallback guidance text.
- Tests: new CLI tests; `guidance-preset-coherence.test.ts` update.
- Docs: `docs/cli-reference.md` decisions section; `CHANGELOG.md`.
- No MCP change: `record_decision` keeps its contract; the CLI calls the same handler.
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
## ADDED Requirements

### Requirement: DecisionsCanBeRecordedFromTheCli

`openlore decisions record` SHALL record a draft architectural decision for the repository in the
current directory, with the same behavior as the `record_decision` MCP tool: the same decision id,
the same scope inference, the same anchors, the same "already decided" verdict for a decision that
consolidation has decided, and the same background consolidation. The command SHALL accept
`--title` and `--rationale` (both required), and `--consequences`, `--files` (comma-separated
paths), `--supersedes`, `--scope` (`local`, `component`, `cross-domain`, or `system`),
`--constraints-file` (a JSON constraint block), and `--json`. The command SHALL work whatever MCP
preset is wired. When the input is not valid or the handler returns an error, the command SHALL
write no draft and SHALL exit with a non-zero code.

Every CLI message that tells the user how to record a decision SHALL name
`openlore decisions record`. When `record_decision` is not part of the wired preset, the generated
agent guidance SHALL name `openlore decisions record` as the way to record a decision.

#### Scenario: Record a draft with default settings

- **GIVEN** a repository wired with the default MCP preset
- **WHEN** the user runs `openlore decisions record --title "Use UUIDs" --rationale "Collision-free ids"`
- **THEN** a draft decision is stored with that title and rationale
- **AND** the output names the draft id and the command that reads its verdict

#### Scenario: JSON output matches the MCP result

- **WHEN** the user runs the command with `--json`
- **THEN** stdout is one JSON object with the same fields the `record_decision` tool returns

#### Scenario: Missing rationale

- **WHEN** the user runs the command without `--rationale`
- **THEN** no draft is stored
- **AND** the command exits with a non-zero code and names the missing option

#### Scenario: Invalid scope or constraint file

- **WHEN** the user passes `--scope wide`, or a `--constraints-file` that is not valid JSON
- **THEN** no draft is stored and the command exits with a non-zero code

#### Scenario: Re-recording a decided decision

- **GIVEN** a decision that consolidation has already promoted, merged, or rejected
- **WHEN** the user records the same decision again
- **THEN** the output reports that verdict and no new draft is created

#### Scenario: Gate message names the command

- **WHEN** the decisions gate blocks a commit for an undocumented change
- **THEN** its message names `openlore decisions record`
- **AND** no CLI message names `openlore decisions --record`

#### Scenario: Guidance without the MCP tool

- **GIVEN** a repository whose wired preset does not include `record_decision`
- **WHEN** agent guidance is generated
- **THEN** the decisions section names `openlore decisions record`
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## 1. Command

- [x] 1.1 Add the `decisions record` subcommand that parses the options and calls the `record_decision` handler for the current directory; verify with a CLI test that a draft is stored and the output names the id and `openlore decisions status <id>`
- [x] 1.2 Validate input before the handler (required `--title`/`--rationale`, `--scope` enum, `--constraints-file` readable JSON object) and exit non-zero on a handler `error`; verify tests for missing rationale, bad scope, and bad JSON store no draft and set a non-zero exit code
- [x] 1.3 Support `--json` (result on stdout, logs on stderr) and forward `--files`, `--supersedes`, `--consequences`; verify a test parses stdout JSON with the handler's fields, and a re-record of a decided decision reports `alreadyDecided`

## 2. Messages and guidance

- [x] 2.1 Replace both `openlore decisions --record` hints with `openlore decisions record`; verify a source test asserts no `decisions --record` string remains under `src/cli`
- [x] 2.2 When `record_decision` is not wired, make the generated decisions section name `openlore decisions record` (keep the enabling-preset hint); verify `guidance-preset-coherence.test.ts` passes with the updated assertions

## 3. Docs and checks

- [x] 3.1 Document the command in `docs/cli-reference.md` and add a `CHANGELOG.md` Unreleased entry; verify the doc-claims guard passes
- [x] 3.2 Run typecheck, lint, and the decisions, guidance, and doc-claims tests; verify all pass and `openspec validate add-decisions-record-cli --strict` passes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-09-15
Loading