feat(cli): support a single-clone global install shared by several CLIs
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 35/100
- Issue type
- Feature
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- git, shell, typescript
- Domain
- cli, developer-experience, documentation, tooling
Research direction
Split the scope into the flat translation, host detection, compatibility command, and documentation concerns before starting. Read plugins/aidd-telemetry/hooks/hooks.json, hooks/lib/host.cjs, hooks/lib/record.cjs, and hooks/lib/repo.cjs, then run the listed translate commands and host probes. Done means the acceptance commands produce declarations and run files, the old command gives migration guidance, and the support table is documented.
Written by the indexing model from the issue text.
Description
Problem
The framework installs per project, through a marketplace and the host's plugin
system. There is no supported path for a machine-wide install shared by several
CLIs from a single clone — which is what a solo developer running four agentic
CLIs side by side actually needs.
Working around it surfaced three concrete gaps, all on v5.10.0 with
@ai-driven-dev/[email protected]:
1. translate --as flat emits hook files but never their declaration.
plugins/aidd-telemetry/hooks/hooks.json declares the three events the journal
needs (SessionStart, Stop, PostToolUse, lines 8/18/28, keyed on
${CLAUDE_PLUGIN_ROOT}). Neither --to claude --as flat nor --to codex --as flat
reproduces it: both write hooks/aidd-telemetry/journal.cjs and its lib/, and no
hooks.json anywhere in the output tree. A hook that is placed but never declared
does not fail — it simply never runs, silently. Outside the plugin runtime that
substitutes ${CLAUDE_PLUGIN_ROOT}, the declaration has to be hand-written into
each host's own config format.
2. Telemetry silently records nothing on two shipping CLIs.
DECLARED_HOSTS (plugins/aidd-telemetry/hooks/lib/host.cjs:25) covers
claude-code, codex, copilot, cursor, opencode. Kimi Code and Antigravity
(agy) are absent, so detectHost returns null and
handleUnrecognisedPayload (lib/record.cjs:255) writes a single
_unrecognised.jsonl marker line instead of a run file. Both CLIs load and run
AIDD skills perfectly well — only the measurement layer cannot read them.
3. framework build was removed without a deprecation path.
CLI 5.x split it: lifecycle stayed on framework, conversion moved to
translate, and the options were renamed (--source → positional, --target →
--to, --flat → --as flat). An install script written against 5.x-minus-one
dies on error: unknown command 'build' with no pointer to the replacement.
Scope
- Document (or support) the single-clone, multi-CLI global install as a first-class
layout, distinct from the per-project marketplace install. - Make
translate --as flatemit each target's hook declaration alongside the hook
files, with absolute paths substituted for${CLAUDE_PLUGIN_ROOT}. - Add Kimi Code and Antigravity to
DECLARED_HOSTSand todetectHost, with the
payload shape each one sends. - Publish the CLI availability matrix below in the docs, so an integrator knows what
is portable before writing a deployment script.
Acceptance criteria
-
aidd translate <src> --to claude --as flat --out <dir>writes a hook
declaration for every hook it installs, with no${CLAUDE_PLUGIN_ROOT}left
unresolved. - Same for
--to codex --as flat. - A session run in Kimi Code produces a run file under
aidd_docs/runs/, not a
_unrecognised.jsonlmarker, when the project has opted in. - Same for Antigravity.
-
aidd framework buildexits with a message namingtranslateand the renamed
options, rather thanunknown command. - The docs carry a per-surface, per-CLI support table.
Prior art in this repo
plugins/aidd-telemetry/hooks/hooks.json— the declaration that exists upstream
and is dropped by the flat layout.plugins/aidd-telemetry/hooks/lib/host.cjs:25—DECLARED_HOSTS.plugins/aidd-telemetry/hooks/lib/record.cjs:250-269— the unrecognised-payload
path, which is exactly why the gap is silent rather than loud.plugins/aidd-telemetry/hooks/lib/repo.cjs:141—telemetryEnabled, the strict
=== trueopt-in gate. Worth noting: the global install stays inert by default
because of this, which is what makes a machine-wide hook acceptable at all.plugins/aidd-context/hooks/update_memory.js— host-agnostic by construction: it
rewrites the open project'sCLAUDE.md/AGENTS.mdand never reads who called
it. This is why it works on all four CLIs while the journal works on two.
Out of scope
- Agent deployment to Antigravity.
agyexposes--agentand anagents
subcommand, butagy agentsreturns nothing and file-based profiles dropped in
~/.gemini/config/agents,~/.gemini/agentsand~/.gemini/config/subagentsare
ignored. Its subagents look internal rather than file-declared — nothing to
deploy until that changes. - Turning measurement on. That stays per project via
.aidd/config.json, as today.
How the global install works
A ~250-line shell script, idempotent, re-runnable. The design decisions are the part
worth discussing — several of them are constraints a framework install --global
would hit too.
One clone is the source of truth, and it is not vendored. The framework lives at
~/dev/aidd-framework; my repo versions how to deploy it, never its content. A
--pull flag fast-forwards the clone, and the version reported is the latest v*
tag — not git describe, which picks up the per-plugin tags (aidd-context-v2.7.0)
first, and not the root package.json, still at 0.0.0.
Two builds, four destinations. translate --to claude --as flat provides the
skills — identical for all four CLIs — plus the Markdown agents and the hooks.
--to codex --as flat is built only to harvest the TOML agents. Everything is
staged in a temp directory first, so a failed build never touches a live config;
when framework build disappeared in CLI 5.x, set -e stopped the run before a
single file moved.
Four skill roots, one format. ~/.claude/skills, ~/.codex/skills,
~/.kimi-code/skills, ~/.gemini/config/skills. All four load the same
<name>/SKILL.md bundle with no translation — this is the single most portable
thing in the framework.
Every write is prefix-scoped to aidd-. Nothing outside that prefix is written
or removed, so a cleanup pass can never eat a hand-written skill living in the same
directory. A bundle that disappears upstream is removed locally: without that, a
renamed skill lingers as a duplicate and keeps being offered to the model. Bundle
directories are replaced wholesale rather than merged — the telemetry hook loads
hooks/lib/, and a module dropped upstream must not survive locally as dead code
the entry point still requires.
The script never writes a CLI's configuration file. ~/.claude/settings.json,
~/.codex/hooks.json, ~/.gemini/settings.json and ~/.kimi-code/config.toml
already carry hooks that are not mine. Instead it verifies two things per file — a
declaration exists, and the path inside it resolves to a real file — and prints the
block to paste when either fails. The second check is the one that matters: a
declaration left pointing at an old path fails silently forever.
One wrinkle worth flagging for anyone automating this: JSON allows \/ for a
forward slash, and one of these files is written in that dialect. Searching for the
hook path verbatim reports a perfectly valid declaration as missing.
A separate consistency checker, at two levels. Disk-only is instant and free: it
fingerprints the aidd- bundles across the four roots and compares them, so a
partial deployment shows up as a fingerprint mismatch. --live adds one real model
call per CLI — the probe opens a skill bundle and asks for the filenames in its
actions/ directory, which fails when the bundle is present but stripped of its
companion files. The two levels do not prove the same thing, and the first does not
replace the second: a CLI that has not been restarted after an update shows a
perfect disk and still sees nothing.
Where the hooks live. ~/.aidd/hooks/, a neutral root — not under ~/.claude/,
which would put Codex's configuration inside another tool's directory. The memory
hook goes to all four CLIs because it never reads who called it; the telemetry
journal goes to two, for the host-detection reason above.
What I measured
One clone of the framework, built twice with translate (--to claude for skills,
Markdown agents and hooks; --to codex for TOML agents), then deployed to four CLIs.
50 skills, 2 agents. Each row below was checked by running the CLI, not by reading
its docs — a probe opens a skill bundle and lists its actions/ directory, so it
fails when the bundle is present but stripped of its companion files.
| Surface | Claude Code | Codex | Kimi Code | Antigravity |
|---|---|---|---|---|
Skills (<name>/SKILL.md) |
yes | yes | yes | yes |
| Agents | yes (.md) |
yes (.toml) |
yes (.md, Claude format verbatim) |
no target format |
Memory hook (update_memory.js) |
yes | yes | yes | yes |
Telemetry hook (journal.cjs) |
yes | yes | no — host unknown | no — host unknown |
The skill bundle format is the portable one: all four load the same
<name>/SKILL.md tree with no translation. Kimi reads the Claude agent Markdown
as-is. Hook declaration is where the four diverge — Claude Code and Codex share a
JSON shape, Antigravity uses a similar JSON under ~/.gemini/settings.json, and
Kimi uses flat TOML [[hooks]] entries.
Happy to open this as separate scoped issues if you would rather validate them one
at a time, and to take the telemetry host-detection one myself.
- Dominant language
- TypeScript
- Stars
- 481
- Forks
- 45
- Avg merge
- 18h 48m
- Merged PRs (30d)
- 111
Getting set up
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from ai-driven-dev/framework
-
refactor(aidd-orchestrator): the check zone says when to stop, and reviews its axes in one roundOpen
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
ai-driven-dev/framework#887 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
ai-driven-dev/framework#873 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
ai-driven-dev/framework#625 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
ai-driven-dev/framework#467 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
ai-driven-dev/framework#921 ·
Maintainers usually reply within 1 day
All issues in ai-driven-dev/framework
Similar issues
-
check:passed streams:add
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Fission-AI/OpenSpec#1986 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
nestjs/docs.nestjs.com#3554 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
publicodes/publicodes#868 ·
-
namespace operations
Difficulty 1/5 Under an hour Newbie friendliness 78/100
EclipseFdn/open-vsx.org#13488 ·
Maintainers usually reply within 2 days