Commit Graph
32 Commits
Author SHA1 Message Date
AkitaOnRails 07b84646b1 docs(claude): distinguish Chat and Cowork hooks
Keep Claude Desktop Chat classified as MCP-only while recording Anthropic’s newer Cowork plugin-hook surface and ai-memory’s current lack of a Cowork integration. References #878.
2026-10-01 15:27:06 -03:00
Test c75af157f1 Address #989 review: split FHS hardening, gate nix CI, slim settings
Drop packaged systemd sandbox changes for a follow-up PR, gate Darwin and
container smoke to schedule/dispatch/nix|full-ci, shrink settings-options
to freeform-friendly keys, escape ExecStart, document llm_headers store
risk and NixOS support-matrix row, and add CODEOWNERS for nix/.
2026-10-01 19:04:07 +03:00
AkitaOnRailsandClaude Opus 5.5 80a78d0255 fix(run): make an explicit ai-jail selection exact with --no-X for unselected rows
The checklist and `--jail=LIST` emitted only enabled toggles, so the user's
own ai-jail config (e.g. a global `~/.ai-jail` enabling `docker`) could still
mount what an unchecked row or an explicit list left out, and the summary
line misreported it.

- Interactive checklist: `marked_choices` passes every row the user saw,
  checked as `--X` and unchecked as `--no-X`.
- `--jail=LIST` (including `none`): after the named entries, every visible
  checklist row the list did not name is forced off with `--no-X`. Rows that
  are not visible (absent credentials, CLI-only toggles) are never forced.
- Bare `--jail` is unchanged: smart-default rows only, the rest left to the
  user's ai-jail config, because no selection was shown.
- `JailToggleChoice::implied` marks rows forced off by omission, so the
  summary names the user's own `no-X` entries and says "everything else in
  the checklist off" for the rest.
- Tests: an adversarial unit test (unchecked docker row and `--jail=none`
  yield `--no-docker` / `--no-*` for every visible row, with bare `--jail`
  as the control); parse, checklist, summary and end-to-end expectations
  updated, the latter platform-aware for the Linux-only rows.
- Docs: design §5 semantics, cookbook, support matrix, CHANGELOG.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-10-01 03:42:50 -03:00
AkitaOnRailsandClaude Opus 5.5 7e0ec65899 feat(run): choose ai-jail toggles with --jail[=LIST], --no-jail, and a checklist
`ai-memory run` can now decide which ai-jail credentials and capabilities a
jailed session gets, from the CLI or an interactive checklist, with smart
defaults so Enter does the friendly thing.

- ai-memory-workstream/jail.rs: a toggle table (credential mounts github,
  aws, kube, gcloud, docker-config; ssh; worktree; docker, gpu, display,
  pictures, tailscale; CLI-only audio, x11, host-shm, terminal-passthrough,
  update-check, mise, toolchains), support detection from the installed
  ai-jail's `--help` (exact `--X` tokens, so `--docker` never matches
  `--docker-config`), injected host facts (home, SSH agent, origin URL,
  linked worktree, project `.ai-jail` presence), the checklist with smart
  defaults, and the `--jail=` list parser (`no-X`, `all`, `none`; reserved
  security switches and ai-memory-owned flags refused).
- build_ai_jail_invocation emits the chosen `--X`/`--no-X` and a
  `--no-save-config` baseline before the `--`, so ai-jail never writes the
  run's transient flags into the repository's `.ai-jail`.
- inspect_repository reports the `origin` URL and whether the cwd is a
  linked worktree.
- run.rs: `--jail[=TOGGLES]` / `--no-jail` (also stripped when they land in
  the native argv), a pure jail_decision table, an explicit `--jail` re-exec
  before the managed run is prepared (failing closed when ai-jail is not
  usable), and the line-based checklist after the `--yolo` offer. A project
  `.ai-jail` replaces the checklist and the bare-`--jail` defaults.
- Tests: unit coverage for parsing, support detection, defaults, the
  decision table, flag stripping, and the checklist grammar; a real
  `ai-jail --dry-run` over every toggle the installed ai-jail advertises;
  end-to-end runs of the built binary with fake ai-jail/bwrap/claude and a
  mock server, including PTY runs of the offer, the checklist, a project
  `.ai-jail`, and `--yolo --no-jail`.
- Docs: design §5, cookbook yolo recipe, support matrix, CHANGELOG.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-10-01 03:32:13 -03:00
AkitaOnRailsandClaude Opus 5.5 013bf691fd docs: fix audited drift in frontend-api, windows, and Codex managed runs
- frontend-api.md (#986): the list, search, and recent routes return bare
  JSON arrays, not `{ "workspaces": … }`-style wrappers (the route tests
  assert `as_array()`); a page read returns `body_markdown`, not `body`; a
  search hit carries workspace/project/kind and no `id`.
- windows.md (#758): native `ai-memory upgrade` is done (#801/#802), not
  in-progress.
- managed-workstreams.md + support matrix (#987): document the Codex shared
  daemon handing hooks a stale AI_MEMORY_RUN_ID and the `--no-daemon`
  workaround until the server-side fix lands.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-10-01 02:47:14 -03:00
AkitaOnRailsandClaude Opus 5.5 ae676d4918 fix(run): ai-jail re-exec/offer, --true-yolo semantics, and relaunch after an interrupted run
ai-jail integration (`ai-memory run --yolo`):
- The re-exec built `ai-jail <flags> <exe> run …` with no `--`. ai-jail
  rejects one of its own flags after the command and `run` shares flag names
  with it, so `run claude --yolo --env GH_TOKEN=…` aborted. The invocation now
  emits `--` before the wrapped exe (forwarding a colliding flag additionally
  needs ai-jail >= 2.4.2, whose guard honors the separator; the cross-tool
  test gates on that version).
- The offer only checked for a file named ai-jail: Windows could show it, a
  host without bwrap/sandbox-exec was offered a jail that cannot start, and a
  ~/.local/bin-only install was offered and then not found by the bare
  `Command::new("ai-jail")` re-exec after the run was already cancelled.
  usable_ai_jail(os, lookup) now returns the exact binary to exec only on
  Linux/macOS with the backend present; otherwise no question is asked.

--true-yolo:
- It now implies --yolo (warning, ai-jail offer, harness dangerous mode):
  alone it used to apply Claude's bypassPermissions with no warning. It is
  interchangeable with --yolo for non-Claude harnesses, and recognized after
  native arguments (`run claude --model opus --true-yolo`), where clap leaves
  it in the native argv and it was forwarded to Claude as an unknown option.
- The claude_true_yolo config key only upgrades an explicit yolo launch, as
  its doc comment stated, instead of bypassing permissions on every run.
- Removed what never worked: three CLAUDE_CODE_DISABLE_*RM* env vars Claude
  Code does not read (absent from the 2.1.280 binary and its env reference),
  and an empty permissions.ask array that cannot clear ask rules from other
  scopes (Claude unions them). Docs now state that Claude honors explicit ask
  rules and its command-safety checks in every permission mode.

Relaunch after an interrupted run:
- A launcher killed before releasing its lease (terminal closed, ai-jail
  torn down) left the workstream held for up to 90s and the next launch failed
  after a 5s retry. An interactive launch now parses the holder and expiry from
  the 409, waits for that lease to lapse (bounded by one lease; Ctrl-C aborts),
  then proceeds. A holder that renews meanwhile is reported as live and never
  displaced; the server's busy check stays the only arbiter (security
  inventory row 13b). Non-interactive launches keep the short window.

Tests: usable_ai_jail OS/backend/Windows/exact-path, `--` placement and the
colliding-flag regression (unit + real ai-jail --dry-run), the yolo_modes
table, --true-yolo in both argv positions via real clap parses, the reduced
true-yolo argv, and HTTP-level held-lease wait / renewed-owner / Ctrl-C cases.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-10-01 01:53:49 -03:00
AkitaOnRailsandClaude Opus 4.8 80888360e2 feat(run): warn before --yolo, offer ai-jail, add Claude true-yolo (#983)
ai-memory run --yolo now, on an interactive TTY only (never in hook/CI/
detached paths):

- warns that --yolo runs every tool call unconfirmed, [Y/n] default-yes;
- offers to re-run inside ai-jail when it is installed, re-execing the
  original argv under `ai-jail --network --agent-state --env <NAME>…`
  (--network shares the host net namespace so the loopback ai-memory server
  stays reachable; only already-set credential/config env is forwarded);
- skips both prompts when already inside ai-jail (Linux hostname ai-sandbox
  / macOS PS1 (jail) ; fails open to showing the warning; Windows never).

Opt-in Claude "true yolo" (--true-yolo / [config] claude_true_yolo,
AI_MEMORY_CLAUDE_TRUE_YOLO) silences the pauses --dangerously-skip-permissions
leaves: sets the CLAUDE_CODE_DISABLE_*_RM_* env vars and injects
--settings bypassPermissions. Claude-only, off by default, sandbox-first.

Detection and argv assembly are pure/OS-explicit (ai-memory-workstream::jail)
with unit tests for every branch; a CLI integration suite asserts the argv
against the real ai-jail via --dry-run (skips cleanly when ai-jail/bwrap are
absent). Design: docs/design-yolo-safety-ai-jail.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-29 15:24:14 -03:00
AkitaOnRails dcf4e6512c Merge PR #944: finalize hookless session on exit (fixes #941)
# Conflicts:
#	docs/support-matrix.md
2026-09-29 12:34:25 -03:00
Gabrigas a6142f9ce3 docs(changelog): record Antigravity CLI tool output resolution (#966) 2026-09-29 05:48:06 -03:00
John Costa 2a14b5db3f feat(run): finalize the session on exit for harnesses without a session-end hook
Command Code, Kiro CLI (v2 and v3) and Antigravity CLI have no native
session-end hook, so their sessions stayed open until a manual
`ai-memory finalize-session`. When `ai-memory run` launched one of them, it
now finalizes the run's own session after the harness exits: the one named
on the command line or chosen before the spawn, or the one its child linked
under AI_MEMORY_RUN_ID in this checkout, never a discovered one.

SessionId::from_native moves the hooks router's native-id mapping into core
so hook POSTs and the lookup share one key. finalize_session::run is split
into finalize() and report printing so the run reports on stderr. The
harness's exit code is kept; finalizing is bounded by a timeout, Ctrl-C
skips it, and a failure prints the exact finalize-session command.
The lookup matches the ended session too (as --reopen does), because these
harnesses keep capturing under the same id after a resume; a re-end with
nothing new is a no-op on the server.

Closes #941
2026-09-28 22:28:33 -07:00
Caminhar 3d84623b98 feat: install Hermes Agent lifecycle hooks
Hermes runs a configured hook command through shlex.split with the event JSON on stdin and no shell, so its integration is exec-form (like Zero and ZCode) rather than a .sh bundle: AgentChoice::Hermes (alias hermes-agent) makes install-hooks, setup-agent and finalize-session accept it, and no script subdir is staged.

build_hermes_hooks_yaml emits the ready-to-paste hooks: block for ~/.hermes/config.yaml with the two events ai-memory can act on - pre_tool_call -> pre-tool-use and post_tool_call -> post-tool-use. Their tool_name / tool_input payload is the envelope the router already maps for agent=hermes, which is what gives Hermes sessions tool observations, tool-family titles and capture exclusions.

install-hooks --agent hermes never writes the config file: it is YAML the operator also edits and Hermes gates user hooks behind its own acceptance prompt (hooks_auto_accept), so the block is printed for pasting - the same choice made for Pool. Session lifecycle is deliberately left to the memory-provider plugin, so no hook-driven session-end is installed and a session cannot be closed twice.

Verified against Hermes v0.21.4: the block parses through Hermes own hermes_yaml, _parse_hooks_block registers both events, split_command_line yields an argv that runs the native hook subcommand, and that command spools the event with rc=0. Docs updated in docs/install.md, docs/support-matrix.md and docs/mcp-install.md. Follow-up to #623.

(cherry picked from commit 18155089cd)
2026-09-27 12:57:03 -03:00
AkitaOnRailsandClaude Opus 4.8 d2da86037f Merge PR #802 into release/2.5
Add native `ai-memory upgrade` for GitHub release installs (#801)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 17:53:46 -03:00
João Carlos Magalhães 4fcca7c8c8 feat(opencode2): bind the plugin to the 2.0.10+ event api with turn checkpoints
OpenCode 2.0.10 replaced the lifecycle events the generated plugin listened
for (session.idle and friends) with session.execution.{succeeded,failed,
interrupted}, and it runs one long-lived service behind every CLI: closing a
terminal is not a session end, so sessions captured through the old binding
rarely produced a summary page or a baton. The plugin also re-ran two `git`
processes per event, lost startup context after the first model request,
dropped content-only tool results, and shared queue and spool state across
the per-location instances OpenCode 2 loads.

Plugin (install_hooks.rs, render_shared.rs, the node host fixture):
- binds session.execution.*, session.text.ended, session.moved,
  session.deleted, session.compaction.started and the context/prompt/tool
  hooks; every name was checked against the OpenCode 2.0.14 binary;
- claims startup context once per root session and re-injects it on every
  model request; child sessions never claim it or publish a baton;
- keeps queue, spool and cleanup state per location instance; spool names
  can no longer collide within a millisecond, and a torn-down host cancels
  what is still in flight only after its final session-ends had the drain
  budget (all generated TypeScript integrations share this runtime now);
- opt-in assistant capture (--capture-assistant) hands the last completed
  text to the native hook, which sanitizes and caps it before the spool or
  the wire, and falls back to the plain stop hook if that binary cannot run.

Server (router.rs, ops.rs, reader.rs, writer.rs):
- a completed root turn is a turn checkpoint: sessions/<id>.md and the
  automatic baton are refreshed deterministically (no LLM) in the session
  row's own scope, keeping one open baton per live session, refreshed in
  place and audited; a checkpoint that lost the race with the session's end
  touches nothing;
- an explicit, keyed session.moved rebinds the live session row to its new
  directory on first delivery (compare-and-set on the cwd it left), so the
  session's end and checkpoints follow it;
- a SessionEnd whose resolved scope drifted under the same cwd (a
  .ai-memory.toml appeared mid-session) ends the session instead of
  stranding it open; scope-drifted ordinary events are recorded as upstream
  records any other drifted event;
- the latest captured assistant excerpt rides in the automatic baton; it is
  not rendered into the git-tracked session page.

Docs: install.md, support-matrix.md, auto-scope.md, SECURITY.md and
DATA_HANDLING.md describe the checkpoint, routing and capture behavior.

Verified: cargo fmt --all -- --check; cargo clippy --workspace --all-targets
-- -D warnings; cargo test --workspace --all-targets (3569 passed, on release/2.5); the node
host fixture runs under cargo test (node >= 22.6) and fails if unload aborts
deliveries before its session-ends. Live on Windows 11 with OpenCode 2.0.14:
after a 64 -> 66 store migration, the running OpenCode service loaded the
regenerated plugin and one real turn through it (a Code Mode call to memory_status)
recorded its prompt, tool events and stop, logged "turn checkpoint written;
native session remains open", left the session open, wrote
sessions/<id>.md and exactly one open baton carrying the captured
assistant excerpt, which the session page does not contain.
2026-09-23 19:52:22 -03:00
Test 335424b742 feat(cli): support native Windows zip self-upgrade
Unify ai-memory upgrade across platforms: map windows-x86_64.zip, allowlisted
zip extract, and rename-aside replace so a running .exe can be updated.
2026-09-23 21:55:22 +03:00
AkitaOnRails 25e92e2633 Merge branch 'pr-840' into release/2.5
# Conflicts:
#	CHANGELOG.md
2026-09-22 15:05:45 -03:00
Giovanni Coutinho 8a6a137c23 docs: Grok handoff is PostToolUse additionalContext
SessionStart still does not accept it. The model sees the note after the
first tool. MCP accept remains the path when no tool runs.
2026-09-21 16:57:51 -03:00
Thiago Macedo eadab8e4bd Add a macOS menu bar companion that bundles and governs the server.
The accessory app ships the ai-memory binary and hooks tree, starts the
existing LaunchAgent, and opens /web, status, config, and logs. Durable
data stays in Application Support so replacing the .app is an update.
2026-09-20 21:25:16 +02:00
wesleycremonini 36db2fad92 docs: fix broken relative links in docs/support-matrix.md, docs/use-cases.md, docs/llm-providers.md
Same bug as the docs/security.md fix in this branch: links written as
if they resolved from the repo root instead of the linking file's own
directory, 404ing on GitHub (e.g. docs/docs/macos.md, docs/docs/install.md).
2026-09-19 21:26:23 -03:00
AkitaOnRailsandClaude Opus 4.8 5337c0254c feat(hooks): Codex assistant-final-turn capture on Stop (#743)
Extend the assistant-capture closed table with (Codex, Stop) → last_assistant_message
(verified on codex-cli 0.154.0), behind the existing double opt-in (client
--capture-assistant + server capture_assistant=true). The install gate
capture_assistant_allowed now admits Codex on a native hook platform (it
previously refused it), and the Codex render path threads --capture-assistant
onto the Stop command. The runtime read + sanitize/bound/backstop/store pipeline
is already agent-agnostic and keys off the closed table, so no new capture code.
Only (Codex, Stop) is added — Codex has no SubagentStop.

Tests: closed-table set updated to admit Codex Stop; a positive
client-transform capture test for Codex; the install-flag gate test admits
Codex; a render test asserting --capture-assistant bakes onto the Codex Stop
command (and only Stop) when opted in. Docs: support-matrix + install.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-15 14:35:29 -03:00
AkitaOnRails 817cde174b Merge PR #711: add Muse Code as an MCP-only install-mcp client (#659)
The MCP-only first increment from #659: install-mcp --client muse writes a
streamable-HTTP entry (with the bearer Authorization header) into Muse's
mcp_servers settings, schema_version-aware and mode:optional. Every field
traced to Meta's published Muse Code docs per the verification asked in #659.

# Conflicts:
#	CHANGELOG.md
2026-09-11 12:59:35 -03:00
Felipe Neves RicardoandClaude Opus 4.8 b4e7d6bf3a feat(install-mcp): add Muse Code as an MCP-only client
Register ai-memory with Meta's Muse Code through its documented
streamable-HTTP transport: a snake_case `mcp_servers` map in
~/.config/muse/settings.json carrying `transport`, `url`, `headers`,
`enabled`, and `mode`.

Two documented constraints shape the writer. The settings file must set
"schema_version": 1 or every muse command fails at startup with
`malformed settings file`, so the key is added when absent and an
existing value is never rewritten — a future schema must not be silently
downgraded. And `mode` defaults to `required`, which aborts the whole
Muse run when the server is unreachable; memory is an augmentation, so
the entry sets "optional" explicitly. No `framing` key is emitted: a
non-default value fails Muse's validation on streamable_http.

MCP-only. Muse documents a lifecycle hook surface, but the output
contract of its SessionStart event is not specified, so capture and
managed workstreams are not claimed and no AgentKind variant or
migration is added. Skills need no new code — Muse reads
~/.agents/skills, which install-skills already writes.

Refs #659

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MHgUwuTjYeDkb1MVjzxA7Z
2026-09-10 18:45:35 -03:00
viniciusdsandrade a2bc64da8c feat(mcp): add memory_handoff_list so no-stdout agents can inspect before claiming
Grok, Zero, and MCP-only clients discard SessionStart stdout, so the only
way to see a pending baton was memory_handoff_accept, which claims it.
List is owner-filtered and read-only; accept now takes an optional
handoff_id so the inspected row is claimed exactly once.
2026-09-06 20:57:40 -03:00
AkitaOnRailsandClaude Opus 4.8 30ef4812f8 Merge PR #622: first-party OpenCode 2.0 beta support [2.1]
Reconciles enrell's #622 onto release/2.1. Additive new-harness feature
(opencode2): new CLI enum arms, wire aliases folded into the existing
AgentKind::OpenCode (no new variant, no migration), a read-only parameterized
SQLite transcript adapter for the beta session_v2/session_message tables, and
an ai-memory-opencode2.ts plugin derived from v1. Sequenced after #625: the
opencode2 plugin inherits #625's resolveToken() auth, so its test assertion is
updated from "Bearer ${TOKEN}" to "Bearer ${token}". CHANGELOG (Added),
mcp-install and support-matrix rows reconciled with the Codex-SessionEnd (#605)
and capture-assistant (#627) wording. Queued for 2.1.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-04 12:16:34 -03:00
AkitaOnRailsandClaude Opus 4.8 8f5abb00a4 Merge main into release/2.1: 2.0.3 batch (#623,#624,#625,#626,#627,#628)
Forward-merges the 2.0.3 fix batch onto the 2.1 train. CHANGELOG (keep-both
Added/Changed/Fixed) and the Codex support-matrix row (SessionEnd wording +
the #627 capture-assistant clarification) reconciled; code auto-merged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-04 12:12:09 -03:00
AkitaOnRailsandClaude Opus 4.8 4181e0b408 docs(support-matrix): note --capture-assistant is Claude-Code-only on the Codex row (#627)
Clarifies that assistant-final-turn capture is Claude Code + native-platform
only (already enforced in install_hooks + documented in install.md); a matrix
reader could otherwise infer capture is universal because only the Claude Code
row mentioned it. #627 was working-as-designed — the installer correctly
refuses --capture-assistant for Codex; this closes the only real doc gap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-04 12:02:36 -03:00
enrell 33b5dd2c2d feat(opencode2): add first-party OpenCode 2.0 beta support
MCP (mcp.servers + oauth:false), dependency-free plugin shape
(ai-memory-opencode2.ts), managed run opencode2, v2 transcript
adapter (session_v2/session_message), acceptance case, docs,
changelog. Shares v1's config dir, session store, and agent kind;
no migration. Verified live against beta-18999.
2026-09-03 23:30:16 -03:00
AkitaOnRailsandClaude Opus 4.8 2ef03ca18c Merge PR #606: operator LLM headers + self-identifying User-Agent [2.1]
Reconciles lucasliet's #606 onto release/2.1 against 2.0.2's #608/#610
opencode header work (only CHANGELOG conflicted; the header code
auto-merged and is verified below). Targets 2.1.0 — holds on the branch
until release.

Adds AI_MEMORY_LLM_HEADERS (typed ExtraHeaders): operator-supplied headers
on every provider, parsed/validated once at the config boundary, fail-closed
against a 9-entry reserved list (authorization, x-api-key, host, ...),
CRLF-rejecting, values marked sensitive, Debug prints names only. Sends
User-Agent: ai-memory/<version> on every provider (Copilot excepted),
layered under operator override; makes 2.0.2's x-opencode-session/user-agent
operator-overridable; and fixes AI_MEMORY_LLM_BASE_URL for provider=opencode
(OPENCODE_ZEN_BASE_URL deprecated for OPENCODE_GO_BASE_URL, value preserved).

Gate on the merged tree: cargo fmt --check clean; clippy --workspace
--all-targets -D warnings clean; full workspace tests 0 failed. #606's
on-the-wire tests and #610's opencode tests pass together.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-03 15:51:15 -03:00
Lucas Oliveira ccdea09f95 fix(llm): let the opencode provider reach Zen, not just Go
`AI_MEMORY_LLM_BASE_URL` had no effect with
`AI_MEMORY_LLM_PROVIDER=opencode`. `OpenCodeProvider::new` hardcoded the
endpoint and `build_provider`'s `OpenCode` arm never read
`ProviderConfig::base_url` — the override was accepted at the configuration
boundary and then silently dropped, which is worse than rejecting it. Zen's
general catalogue at `https://opencode.ai/zen/v1` was unreachable through
the provider built for OpenCode; the only route was `openai-compat`, which
gives up the `x-opencode-session` default.

Zen and Go are separate products, not two spellings of one: Go serves a
smaller, cost-optimised model set under `zen/go/v1`, Zen the full catalogue
under `zen/v1`. The constant said one and held the other
(`OPENCODE_ZEN_BASE_URL = ".../zen/go/v1"`), and the docs repeated the
conflation as "Zen/Go" throughout, so the gap was invisible from the code.

- `OPENCODE_GO_BASE_URL` names the default endpoint for what it is.
  `OPENCODE_ZEN_BASE_URL` is deprecated in favour of it but keeps both its
  export and its value, so code compiled against v2.0 is unaffected.
- `OpenCodeProvider::with_base_url` repoints the provider, and the factory
  calls it with `ProviderConfig::base_url`, mirroring how the
  `anthropic-oauth` arm already handles its own override. Go stays the
  default, so existing setups do not move.
- An override keeps the session header and the user agent: both endpoints
  correlate requests the same way, so changing where a request goes must not
  change how it identifies itself.
- Docs distinguish the two products and state that model ids are per
  catalogue, so an override needs an explicit `AI_MEMORY_LLM_MODEL`. The
  `opencode-zen` alias selects Go like every other spelling — the endpoint
  comes from the base URL, not the alias — and now says so.

Unit tests pin the default, the alias's value, the override, and that the
session header survives it; a wiremock test drives `build_provider` and
asserts the request actually arrives at the overridden host carrying both
headers, since "the field changed" and "the request went elsewhere" are
different claims.
2026-09-03 14:26:36 +00:00
holocasterandClaude Sonnet 5 e37becbaf6 feat(install-hooks): wire Codex SessionEnd hook (Codex CLI 0.145.0)
Codex shipped a first-class SessionEnd lifecycle event in Codex CLI
0.145.0 (openai/codex#33895). ai-memory already bundled
hooks/codex/session-end.{sh,ps1} but never listed the event in
CODEX_EVENTS, so finished Codex sessions got no automatic
end-of-session summary or cross-agent handoff.

Add ("SessionEnd", "session-end.sh") to CODEX_EVENTS and stop
merge_codex_payload from unconditionally stripping the key on every
apply -- it now goes through overlay_event_hooks like every other
event, so a user's own third-party SessionEnd hook is preserved and
ai-memory's entry is added alongside it. The .ps1 is picked up by the
existing Windows extension swap. Update the Codex support-matrix row
and add a CHANGELOG entry.

On Codex < 0.145 the event key is inert; finalize-session --agent codex
remains the documented fallback.

Closes #604

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HHRmTUMXVVcG1MsyRXTcQp
2026-09-03 09:15:11 -03:00
AkitaOnRailsandClaude Fable 5 0daf341579 Merge branch 'main' into pr-569; port the launchd note to the split-out support matrix
The README support matrix moved to docs/support-matrix.md in the 2.0
docs rework; the PR's macOS-row addition lands there instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-02 00:33:59 -03:00
AkitaOnRailsandClaude Fable 5 0b35ed873e docs: the why/when pass - adoption guidance over feature lists (item 8)
Every user-facing doc was graded on four axes (what / why / when-to /
real example, including when-NOT-to). Fixes for the highest-impact
gaps:

- managed-workstreams: 'Do you need this?' - hooks + handoffs already
  cover the quit-Claude-open-Codex case; managed runs are for native
  resume surviving a harness switch. Skip guidance included.
- auto-improvement-loop: a 60-second user-facing top for a feature that
  is on by default - what auto-approve means, the explicit
  require_approval=true recommendation for shared/team servers, cost
  shape, and what a staged proposal sidecar contains. Research prose
  retained below the fold.
- okf: opens with the user payoff (hand a bundle to someone without
  ai-memory; export-okf one-liner; what the receiving side sees)
  before the conformance design.
- temporal: when to reach for as_of (audits/post-mortems; plain
  memory_query is right 99% of the time) plus a worked
  postgres-then-migrated example with both results.
- typed-edges: the gotcha->fixes->contradicts->lint loop as a concrete
  scenario, and 'plain wikilinks remain the default' skip guidance.
- experience: a sample staged cross-session proposal.
- config template: consolidation and slots blocks say why/when, not
  just what.

Accuracy bugs found by the same sweep: auto-scope's config snippet
still called mode="single" the default (per_actor since v1.39); ZCode
was listed twice with conflicting statuses in both support matrices
(it has MCP #529 AND hooks #532 - merged to one Supported row); the
README docs index listed ROADMAP-2.0 twice.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-01 20:10:53 -03:00
AkitaOnRailsandClaude Fable 5 b1595623c0 docs(readme): lead with the differentiators, move detail into linked docs
The README had grown to 1,125 lines and buried the case for the project
under installation detail. Rebuilt it at a third of the size:

- New "Why ai-memory" section up top - the five differentiators the
  September 2026 landscape research validated (cross-agent handoffs as a
  typed protocol, cross-machine continuity, team sharing with auth and
  attribution, plain-markdown source of truth, silent zero-LLM capture),
  written for a human reader rather than as a feature list, plus an
  honest-ops note with the measured ~700/s write ceiling.
- New "How it works" capture->consolidate->recall->handoff flow.
- Support matrix compacted to two columns; the full 30+-row per-agent
  matrix moved verbatim to docs/support-matrix.md.
- Quick start trimmed to AUR + docker + the two claude-code wiring
  commands; stale "enable per_session for two sessions" advice replaced
  with the v1.39 works-out-of-the-box story.
- Use cases, LLM providers, and security hardening moved verbatim to
  docs/use-cases.md, docs/llm-providers.md, docs/security.md, each linked
  from a short pointer section and from the Docs index.

Verbatim moves only - no prose was rewritten in the extracted docs.
Packaging tests (36) still pass; README keeps zero mutable-main install
URLs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-01 02:02:15 -03:00