Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

feat(cli): support a single-clone global install shared by several CLIs

Closed
#859 3 comments 0 reactions 0 assignees View on GitHub

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

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 flat emit each target's hook declaration alongside the hook
    files, with absolute paths substituted for ${CLAUDE_PLUGIN_ROOT}.
  • Add Kimi Code and Antigravity to DECLARED_HOSTS and to detectHost, 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.jsonl marker, when the project has opted in.
  • Same for Antigravity.
  • aidd framework build exits with a message naming translate and the renamed
    options, rather than unknown 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
    === true opt-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's CLAUDE.md / AGENTS.md and 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. agy exposes --agent and an agents
    subcommand, but agy agents returns nothing and file-based profiles dropped in
    ~/.gemini/config/agents, ~/.gemini/agents and ~/.gemini/config/subagents are
    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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from ai-driven-dev/framework

All issues in ai-driven-dev/framework

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.