diff --git a/.github/workflows/plugin.yml b/.github/workflows/plugin.yml index b71a4b1..e9b84a1 100644 --- a/.github/workflows/plugin.yml +++ b/.github/workflows/plugin.yml @@ -2,9 +2,25 @@ name: plugin on: push: branches: [main] - paths: ["plugin/**", ".claude-plugin/**", ".github/workflows/plugin.yml"] + paths: + - "plugin/**" + - "skills/**" + - "src/cairn/assets/**" + - ".claude-plugin/**" + - ".agents/plugins/**" + - "tests/test_plugin_assets.py" + - "tests/test_skill_distribution.py" + - ".github/workflows/plugin.yml" pull_request: - paths: ["plugin/**", ".claude-plugin/**", ".github/workflows/plugin.yml"] + paths: + - "plugin/**" + - "skills/**" + - "src/cairn/assets/**" + - ".claude-plugin/**" + - ".agents/plugins/**" + - "tests/test_plugin_assets.py" + - "tests/test_skill_distribution.py" + - ".github/workflows/plugin.yml" jobs: validate: runs-on: ubuntu-latest @@ -15,7 +31,36 @@ jobs: python-version: "3.12" # --with pytest provisions pytest into the isolated env; the plugin tests # read only JSON/Markdown (no cairn package), so --no-project keeps CI fast. - - run: uv run --no-project --with pytest pytest plugin/tests/ -q + - run: >- + uv run --no-project --with pytest pytest + --noconftest + plugin/tests/ + tests/test_plugin_assets.py + tests/test_skill_distribution.py + -q + - name: Verify isolated skills.sh installation + env: + DISABLE_TELEMETRY: "1" + run: | + fake_home="$(mktemp -d)" + export HOME="$fake_home" + export XDG_STATE_HOME="$RUNNER_TEMP/skills-state" + export npm_config_cache="$RUNNER_TEMP/npm-cache" + export npm_config_ignore_scripts="true" + npx --yes skills@1.5.19 add "$GITHUB_WORKSPACE" \ + --agent codex --global --yes --copy + test -f "$fake_home/.agents/skills/agentcairn-setup/SKILL.md" + test -f "$fake_home/.agents/skills/agentcairn-setup/agents/openai.yaml" + test ! -e "$fake_home/.agents/skills/using-agentcairn-memory" + unexpected="$(find "$fake_home" -type f \ + ! -path "$fake_home/.agents/skills/agentcairn-setup/SKILL.md" \ + ! -path "$fake_home/.agents/skills/agentcairn-setup/agents/openai.yaml" \ + -print)" + if [ -n "$unexpected" ]; then + echo "skills.sh wrote unexpected files:" >&2 + echo "$unexpected" >&2 + exit 1 + fi - name: shellcheck hook scripts run: | sudo apt-get update && sudo apt-get install -y shellcheck diff --git a/CHANGELOG.md b/CHANGELOG.md index c533983..c565a22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,24 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning: [S ## [Unreleased] +### Added +- **Agent-assisted setup through skills.sh.** The public `agentcairn-setup` + skill discovers the current harness, previews one targeted native install, + delegates all writes to `cairn install`, and verifies the runtime, plugin/MCP + layer, restart boundary, and loaded tools. It remains setup guidance only; + native plugins and the AgentCairn CLI continue to own runtime installation. + +### Changed +- The plugin-delivered `using-agentcairn-memory` skill is internal to normal + skills.sh discovery and now fails closed when its MCP tools are unavailable, + directing users to the setup assistant instead of implying that a standalone + behavior skill installed the runtime. Native plugin manifests advance to + Claude Code 0.4.1, Codex 0.1.3, and Antigravity 0.1.2. + +### Fixed +- Correct the Hermes index-rebuild example to pass the vault as the positional + argument to `cairn reindex`. + ## [0.25.0] - 2026-07-16 ### Added diff --git a/README.md b/README.md index 26ca0c4..7c21abe 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,18 @@ codex plugin add agentcairn@agentcairn Codex gets the bundled MCP tools and memory skill, live-verified SessionStart recall, and SessionEnd capture with `cairn sweep` as the out-of-band backstop. +### Agent-assisted setup + +Already use [skills.sh](https://skills.sh/) or a `find-skills` workflow? Install the public setup assistant: + +```bash +npx skills add ccf/agentcairn --skill agentcairn-setup -g +``` + +Then ask your agent: `Use $agentcairn-setup to preview, install, and verify AgentCairn for this coding agent.` + +This installs setup guidance only—not the AgentCairn runtime, MCP server, plugin, or hooks. The assistant delegates those changes to AgentCairn's preview-first native installer and verifies the resulting integration. The Claude Code and Codex plugin commands above remain the shortest path. + The default vault is `~/agentcairn` and is created on first use. A new empty vault has nothing useful to recall yet, so prove the whole loop explicitly: ```text diff --git a/integrations/hermes/README.md b/integrations/hermes/README.md index 095a687..b90995e 100644 --- a/integrations/hermes/README.md +++ b/integrations/hermes/README.md @@ -58,7 +58,7 @@ The optional LLM judge (`CAIRN_JUDGE=anthropic` + `ANTHROPIC_API_KEY`) applies t To rebuild the index from the Markdown files alone (e.g., after moving the vault or upgrading agentcairn): ```bash -cairn reindex --vault ~/agentcairn +cairn reindex ~/agentcairn ``` ## Notes diff --git a/plugin/.claude-plugin/plugin.json b/plugin/.claude-plugin/plugin.json index e1de30f..33d6d45 100644 --- a/plugin/.claude-plugin/plugin.json +++ b/plugin/.claude-plugin/plugin.json @@ -2,7 +2,7 @@ "name": "agentcairn", "displayName": "agentcairn", "description": "Local-first agent memory for Claude Code — recall, remember, and ambient capture into a Markdown vault you own.", - "version": "0.4.0", + "version": "0.4.1", "author": { "name": "Charles C. Figueiredo", "email": "ccf@ccf.io" }, "homepage": "https://agentcairn.dev", "repository": "https://github.com/ccf/agentcairn", diff --git a/plugin/.codex-plugin/plugin.json b/plugin/.codex-plugin/plugin.json index 6a0ee8b..4affa5b 100644 --- a/plugin/.codex-plugin/plugin.json +++ b/plugin/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "agentcairn", - "version": "0.1.2", + "version": "0.1.3", "description": "Local-first agent memory for Codex — recall, remember, and ambient capture into a Markdown vault you own.", "author": { "name": "Charles C. Figueiredo", "email": "ccf@ccf.io" }, "homepage": "https://agentcairn.dev", diff --git a/plugin/plugin.json b/plugin/plugin.json index bf68649..393d5d1 100644 --- a/plugin/plugin.json +++ b/plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "agentcairn", - "version": "0.1.1", + "version": "0.1.2", "description": "Local-first agent memory for Antigravity — recall, remember, and ambient capture into a Markdown vault you own.", "author": { "name": "Charles C. Figueiredo", "email": "ccf@ccf.io" }, "homepage": "https://agentcairn.dev", diff --git a/plugin/skills/using-agentcairn-memory/SKILL.md b/plugin/skills/using-agentcairn-memory/SKILL.md index 8b0f7c9..db64fdc 100644 --- a/plugin/skills/using-agentcairn-memory/SKILL.md +++ b/plugin/skills/using-agentcairn-memory/SKILL.md @@ -1,12 +1,29 @@ --- name: using-agentcairn-memory -description: Use when starting a non-trivial task or finishing a decision/fix — recall prior memory before working, and remember durable facts worth carrying across sessions. +description: Use when AgentCairn memory tools are loaded and starting a non-trivial task or finishing a decision/fix — recall prior memory before working, and remember durable facts worth carrying across sessions. +metadata: + internal: true --- # Using agentcairn memory You have a persistent memory backed by agentcairn (a Markdown vault the user owns). Use it. +## Require the full integration + +This skill assumes AgentCairn's MCP tools are already loaded. Before following +the memory workflow, confirm that `recall` and `remember` are available. + +If the tools are missing: + +- Do not invent tool calls or imply that this behavior skill installed the + AgentCairn runtime, MCP server, plugin, or hooks. +- Explain that the full AgentCairn integration is not loaded. +- Invoke `$agentcairn-setup` if available, or direct the user to the native + AgentCairn installation instructions. +- Stop the memory workflow until installation is complete and the host has been + restarted. + ## Recall before you work Before designing, debugging, or re-deriving something non-trivial, **search memory first**: - Use the `recall` tool (hybrid search) with a focused query — "how did we fix the auth token refresh?", "what did we decide about the migration order?". diff --git a/skills/agentcairn-setup/SKILL.md b/skills/agentcairn-setup/SKILL.md new file mode 100644 index 0000000..94e9e24 --- /dev/null +++ b/skills/agentcairn-setup/SKILL.md @@ -0,0 +1,172 @@ +--- +name: agentcairn-setup +description: Install, configure, verify, upgrade, or repair AgentCairn persistent cross-agent memory. Use when a user wants shared local-first memory in Claude Code, Codex, Cursor, OpenCode, Antigravity, VS Code, Claude Desktop, or another supported harness; when AgentCairn recall or remember tools are missing; or when its plugin, MCP server, skill, or ambient hooks need setup diagnostics. +--- + +# AgentCairn setup + +Set up the full AgentCairn integration by delegating to AgentCairn's native, +preview-first installer. Treat this skill as a management layer only: installing +this skill does not install the AgentCairn runtime, MCP server, plugin, or hooks. + +## Preserve the boundary + +- Use `uvx --from agentcairn cairn install` as the source of truth for supported + hosts and generated configuration. +- Do not copy plugin files, write MCP configuration by hand, or reproduce the + installer's host-specific logic. +- Do not claim AgentCairn is ready merely because this setup skill is present. +- Do not use plain `uvx cairn`; that resolves an unrelated package. Use + `uvx --from agentcairn cairn ...`. +- Use `--vault` only for MCP hosts. Configure plugin-host vaults through the + plugin or AgentCairn's shared configuration. +- Do not install or repair every detected host unless the user explicitly asks. +- Do not write a test memory without the user's approval. + +## 1. Establish the target + +Check whether AgentCairn's `recall` and `remember` MCP tools are already loaded. +If they are available and the user did not request an upgrade or repair, report +that the full integration is active and move to verification. + +Identify the current or requested host. Use these installer IDs: + +| Host | Installer ID | Integration | +|---|---|---| +| Claude Code | `claude-code` | Native plugin, MCP tools, skill, and hooks | +| Codex | `codex` | Native plugin, MCP tools, skill, and hooks | +| Cursor | `cursor` | MCP configuration and memory skill | +| OpenCode | `opencode` | MCP configuration, commands, and native plugin | +| Antigravity | `antigravity` | Native plugin; requires a local plugin source | +| VS Code / Copilot | `vscode` | MCP configuration | +| Claude Desktop | `claude-desktop` | MCP configuration | +| Gemini CLI | `gemini` | MCP configuration | + +Treat Hermes Agent separately because it uses a native `MemoryProvider`, not +`cairn install`: + +```bash +hermes plugins install ccf/agentcairn/integrations/hermes +hermes memory setup agentcairn +``` + +If the target is still ambiguous after inspecting the current harness and +installed CLIs, ask the user which one to configure. Never choose `--all` as a +shortcut. + +## 2. Check the prerequisite + +Run: + +```bash +uvx --version +``` + +If `uvx` is missing, explain that AgentCairn uses Astral's `uv` and ask before +installing a system-level prerequisite. Do not silently run a remote installer. + +Confirm the AgentCairn package and CLI resolve: + +```bash +uvx --from agentcairn cairn --version +``` + +## 3. Preview without changing host configuration + +Use discovery mode to list detected hosts. It writes no AgentCairn host +configuration, but detection proves only that a host is present—not that +AgentCairn is installed or healthy: + +```bash +uvx --from agentcairn cairn install +``` + +For a plugin host, preview the exact target: + +```bash +uvx --from agentcairn cairn install --print +``` + +This prints only the native plugin commands. For MCP hosts, the same `--print` +operation prints the complete merged configuration and may include credentials +from unrelated MCP servers. Do not run it directly through a chat-visible tool +or paste its output into an agent transcript. Ask the user to review it in +their own terminal, or redirect it to a mode-`0600` temporary file, inspect only +the AgentCairn entry locally, and remove the temporary file. + +For Antigravity, first locate a local checkout of the AgentCairn plugin and +preview with its path: + +```bash +uvx --from agentcairn cairn install antigravity --source /plugin --print +``` + +Summarize the plugin commands or configuration path shown by the preview +without exposing unrelated configuration values. If the user has not already +authorized the installation or repair, get approval before continuing. + +## 4. Apply one targeted installation + +Run the same operation without `--print`: + +```bash +uvx --from agentcairn cairn install +``` + +For Antigravity, retain the reviewed local source: + +```bash +uvx --from agentcairn cairn install antigravity --source /plugin +``` + +For Claude Code and Codex, let the installer delegate to the host's plugin CLI. +Confirm the requested plugin host's CLI is available before applying. For MCP +hosts, let the installer perform its backup-first, merge-preserving +configuration write. Treat a failed command as a failed install; report its +last useful error instead of continuing as though setup succeeded. + +## 5. Verify the full integration + +Verify each layer that the host supports: + +1. Confirm the install command exited successfully. +2. For Claude Code, run `claude plugin list --json`; for Codex, run + `codex plugin list --json`. Confirm `agentcairn` is installed and enabled. +3. For an MCP-configured host, confirm its AgentCairn entry matches the + privately reviewed targeted `--print` preview without removing unrelated + configuration. +4. Restart the host. A running session cannot reliably hot-load a new plugin, + MCP server, skill, or hook. +5. In a fresh session, confirm the AgentCairn `search`, `recall`, + `build_context`, `recent`, and `remember` tools are present. Use `recent` or + a focused read-only recall to exercise the MCP server. Ask before writing + and recalling a synthetic memory. +6. If a vault index already exists, optionally run + `uvx --from agentcairn cairn doctor --vault ` to check index health. + Do not treat an empty, not-yet-indexed vault as a plugin failure. + +Report partial support honestly. MCP tools working does not prove ambient hooks +loaded; a setup skill loading does not prove the MCP tools exist. + +## Repair or upgrade + +Start again from the targeted `--print` preview and preserve the same host ID +and vault. For MCP hosts, rerun the targeted installer; its writes are +idempotent, backup-first, and preserve unrelated servers. + +For native plugin hosts, refresh through the host's own plugin manager before +restarting: + +```bash +# Codex +codex plugin marketplace upgrade agentcairn +codex plugin add agentcairn@agentcairn + +# Claude Code +claude plugin marketplace update agentcairn +claude plugin update agentcairn@agentcairn +``` + +Do not remove an existing integration, delete a vault, or overwrite a malformed +configuration as a repair shortcut. Surface the conflict and ask before any +destructive recovery. diff --git a/skills/agentcairn-setup/agents/openai.yaml b/skills/agentcairn-setup/agents/openai.yaml new file mode 100644 index 0000000..8929016 --- /dev/null +++ b/skills/agentcairn-setup/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "AgentCairn Setup" + short_description: "Install and repair persistent cross-agent memory" + default_prompt: "Use $agentcairn-setup to preview, install, and verify AgentCairn for my current coding agent." diff --git a/src/cairn/assets/using-agentcairn-memory/SKILL.md b/src/cairn/assets/using-agentcairn-memory/SKILL.md index 8b0f7c9..db64fdc 100644 --- a/src/cairn/assets/using-agentcairn-memory/SKILL.md +++ b/src/cairn/assets/using-agentcairn-memory/SKILL.md @@ -1,12 +1,29 @@ --- name: using-agentcairn-memory -description: Use when starting a non-trivial task or finishing a decision/fix — recall prior memory before working, and remember durable facts worth carrying across sessions. +description: Use when AgentCairn memory tools are loaded and starting a non-trivial task or finishing a decision/fix — recall prior memory before working, and remember durable facts worth carrying across sessions. +metadata: + internal: true --- # Using agentcairn memory You have a persistent memory backed by agentcairn (a Markdown vault the user owns). Use it. +## Require the full integration + +This skill assumes AgentCairn's MCP tools are already loaded. Before following +the memory workflow, confirm that `recall` and `remember` are available. + +If the tools are missing: + +- Do not invent tool calls or imply that this behavior skill installed the + AgentCairn runtime, MCP server, plugin, or hooks. +- Explain that the full AgentCairn integration is not loaded. +- Invoke `$agentcairn-setup` if available, or direct the user to the native + AgentCairn installation instructions. +- Stop the memory workflow until installation is complete and the host has been + restarted. + ## Recall before you work Before designing, debugging, or re-deriving something non-trivial, **search memory first**: - Use the `recall` tool (hybrid search) with a focused query — "how did we fix the auth token refresh?", "what did we decide about the migration order?". diff --git a/tests/test_skill_distribution.py b/tests/test_skill_distribution.py new file mode 100644 index 0000000..982153c --- /dev/null +++ b/tests/test_skill_distribution.py @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: Apache-2.0 +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +SETUP = ROOT / "skills" / "agentcairn-setup" +RUNTIME = ROOT / "plugin" / "skills" / "using-agentcairn-memory" / "SKILL.md" +RUNTIME_PACKAGE_COPY = ROOT / "src" / "cairn" / "assets" / "using-agentcairn-memory" / "SKILL.md" + + +def _frontmatter(text: str) -> dict[str, str]: + assert text.startswith("---\n") + raw = text.split("---\n", 2)[1] + fields: dict[str, str] = {} + for line in raw.splitlines(): + if line and not line.startswith(" ") and ":" in line: + key, value = line.split(":", 1) + fields[key] = value.strip() + return fields + + +def test_public_setup_skill_has_a_valid_interface(): + text = (SETUP / "SKILL.md").read_text(encoding="utf-8") + fields = _frontmatter(text) + assert fields.keys() == {"name", "description"} + assert fields["name"] == "agentcairn-setup" + assert all(word in fields["description"].lower() for word in ("install", "verify", "repair")) + + interface = (SETUP / "agents" / "openai.yaml").read_text(encoding="utf-8") + assert 'display_name: "AgentCairn Setup"' in interface + assert "$agentcairn-setup" in interface + files = {path.relative_to(SETUP).as_posix() for path in SETUP.rglob("*") if path.is_file()} + assert files == {"SKILL.md", "agents/openai.yaml"} + + +def test_public_setup_skill_delegates_instead_of_bundling_an_installer(): + text = (SETUP / "SKILL.md").read_text(encoding="utf-8") + prose = " ".join(text.split()) + assert "installing this skill does not install" in prose + assert "uvx --from agentcairn cairn install" in text + assert "uvx --from agentcairn cairn install --print" in text + assert "Do not copy plugin files, write MCP configuration by hand" in prose + assert "Do not install or repair every detected host" in prose + assert "may include credentials from unrelated MCP servers" in prose + assert not (SETUP / "scripts").exists() + + +def test_setup_skill_is_not_loaded_as_native_runtime_behavior(): + assert not (ROOT / "plugin" / "skills" / "agentcairn-setup").exists() + + +def test_runtime_skill_is_internal_and_fails_closed_without_tools(): + text = RUNTIME.read_text(encoding="utf-8") + assert "metadata:\n internal: true" in text + assert "confirm that `recall` and `remember` are available" in text + assert "Do not invent tool calls" in text + assert "$agentcairn-setup" in text + assert "restarted" in text + assert RUNTIME.read_bytes() == RUNTIME_PACKAGE_COPY.read_bytes()