talking-stick 0.4.12 → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -12
- package/dist/cli/install-commands.js +101 -16
- package/dist/cli/output.js +2 -2
- package/dist/cli/parser.js +1 -0
- package/dist/cli/registry.js +1 -1
- package/dist/harness-model.js +44 -0
- package/dist/identity.js +11 -8
- package/dist/index.js +3 -2
- package/dist/install-migration.js +7 -1
- package/dist/install.js +14 -1
- package/dist/instructions.js +14 -5
- package/dist/skill-install.js +200 -28
- package/dist/update-migration.js +11 -1
- package/docs/plans/2026-06-13-antigravity-agents-skill-install.md +793 -0
- package/docs/releases/0.4.13.md +25 -0
- package/package.json +1 -1
- package/skills/talking-stick/SKILL.md +2 -2
|
@@ -0,0 +1,793 @@
|
|
|
1
|
+
# Plan: Antigravity (agy) harness support + shared `~/.agents/skills` install trimming
|
|
2
|
+
|
|
3
|
+
- **Date:** 2026-06-13
|
|
4
|
+
- **Author:** Claude (draft) + Codex (adversarial review) + Claude (convergence) + Claude (convergence review)
|
|
5
|
+
- **Status:** IMPLEMENTED & VERIFIED (2026-06-14). All §12.5 steps 1-9 done. Codex implemented; Claude
|
|
6
|
+
reviewed + tested. Verification: typecheck clean, 386 tests pass, build clean, antigravity identity
|
|
7
|
+
(conversation-id + trajectory fallback) confirmed, real `tt install --all` dogfood migrated to shared
|
|
8
|
+
`~/.agents/skills/talking-stick` + pruned codex/grok/opencode duplicates (claude proprietary & gemini
|
|
9
|
+
symlink left intact), Option B uninstall confirmed (single-harness leaves shared + hint; `agents`/
|
|
10
|
+
`--shared`/`--all` remove shared). §13.2 resolved Option B. SHIPPED to branch `antigravity-agents-skill`
|
|
11
|
+
(feature commit 0c2f3ca + version commit c0f82b1, tag v0.4.13 pushed; draft GitHub release created).
|
|
12
|
+
REMAINING (operator-gated): `npm publish` (2FA), publish the draft release, and land the branch on
|
|
13
|
+
master (prefer fast-forward/merge over squash to keep tag v0.4.13 valid).
|
|
14
|
+
- **Phase:** draft -> adversarial review -> convergence (done) -> implementation
|
|
15
|
+
- **Scope:** Planning only. No code changes in this turn beyond this document.
|
|
16
|
+
- **Implementation entry point:** §12 (converged decisions) is authoritative; §1-11 are the
|
|
17
|
+
reasoning trail. Build from §12.5 (build sequence).
|
|
18
|
+
|
|
19
|
+
## 1. Summary / goals
|
|
20
|
+
|
|
21
|
+
Two coupled changes:
|
|
22
|
+
|
|
23
|
+
1. **Add Antigravity CLI (`agy`) as a first-class harness**, replacing the now-deprecated
|
|
24
|
+
Gemini CLI. Antigravity announces itself with env markers `ANTIGRAVITY_AGENT=1`,
|
|
25
|
+
`ANTIGRAVITY_CONVERSATION_ID`, and `ANTIGRAVITY_TRAJECTORY_ID`.
|
|
26
|
+
2. **Trim skill-install behavior so Talking Stick does not create duplicate or conflicting
|
|
27
|
+
`talking-stick` skill entries** for harnesses that load skills from a shared
|
|
28
|
+
`~/.agents/skills` directory in addition to (or instead of) their proprietary
|
|
29
|
+
`~/.<harness>/skills` folder.
|
|
30
|
+
|
|
31
|
+
These are coupled because the most likely reason Antigravity matters here is that Antigravity
|
|
32
|
+
reads the shared `~/.agents/skills` location rather than a proprietary folder, which is exactly
|
|
33
|
+
the duplication problem we need to solve generally.
|
|
34
|
+
|
|
35
|
+
The two changes share one root design decision: **install the skill once per physical location,
|
|
36
|
+
keyed by a per-harness "skill loading model," instead of once per harness name.**
|
|
37
|
+
|
|
38
|
+
## 2. Current state (evidence)
|
|
39
|
+
|
|
40
|
+
All paths below are in this repo at the time of writing (package version 0.4.12).
|
|
41
|
+
|
|
42
|
+
### 2.1 Harness enumeration is duplicated across several modules
|
|
43
|
+
|
|
44
|
+
There is no single registry of harnesses; the set is re-declared per concern, so adding/removing
|
|
45
|
+
a harness touches many files:
|
|
46
|
+
|
|
47
|
+
- `src/install.ts:7` — `SUPPORTED_HARNESSES = ["claude-code", "codex", "gemini", "grok", "opencode"]`
|
|
48
|
+
(install ids; drives `tt install`, `--all`, `parseHarnessList`, stale-MCP cleanup).
|
|
49
|
+
- `src/skill-install.ts:15` — `FILE_SKILL_HARNESSES = ["claude-code", "codex", "grok", "opencode"]`
|
|
50
|
+
(harnesses that get a **file** skill install — copy/symlink into a proprietary folder). Gemini
|
|
51
|
+
is deliberately excluded because it is registry-managed.
|
|
52
|
+
- `src/identity.ts:58` — `HarnessCliHarness = "claude" | "codex" | "gemini" | "grok" | "opencode"`
|
|
53
|
+
(CLI identity prefixes / display names).
|
|
54
|
+
- `src/identity.ts:406` — `HARNESS_COMMAND_MAPPING` maps process-command labels
|
|
55
|
+
(`claude`, `claude-code`, `codex`, `gemini`, `grok`, `opencode`) → harness, used by ancestry walking.
|
|
56
|
+
- `src/instructions.ts:8` — `InstructionHarness` union includes `gemini`.
|
|
57
|
+
- `src/instructions.ts:95` — `HARNESS_ALIASES` (`gemini: "gemini"`, etc.).
|
|
58
|
+
- `src/instructions.ts:82` — `## Gemini` section inside `DEFAULT_INSTRUCTIONS_MARKDOWN`, plus the
|
|
59
|
+
prose line at `src/instructions.ts:68` ("Gemini and OpenCode start with conservative local guidance...").
|
|
60
|
+
- `src/cli/output.ts:204` — help text enumerates `claude|codex|gemini|grok|opencode`.
|
|
61
|
+
|
|
62
|
+
### 2.2 How identity detection works (Gemini today)
|
|
63
|
+
|
|
64
|
+
- `detectHarnessSignal` (`src/identity.ts:444`) checks env markers in order: `CLAUDECODE`,
|
|
65
|
+
`CODEX_MANAGED_BY_NPM`/`CODEX_THREAD_ID`, `GEMINI_CLI` (`src/identity.ts:459`), `OPENCODE`, then
|
|
66
|
+
cmux launch kind. Gemini returns `{ harness: "gemini", sessionId: null, pidHint: null }` — it has
|
|
67
|
+
**no env session id**, so the session id falls back to ancestry root pid/startTime
|
|
68
|
+
(`resolveHarnessSessionId`, `src/identity.ts:272`).
|
|
69
|
+
- Ancestry detection (`detectHarnessViaAncestry`, `src/identity.ts:415`) and
|
|
70
|
+
`findHarnessRootInAncestry` (`src/identity.ts:346`) rely on `HARNESS_COMMAND_MAPPING`, i.e. a
|
|
71
|
+
process whose command basename is `gemini`.
|
|
72
|
+
|
|
73
|
+
### 2.3 How skill install works
|
|
74
|
+
|
|
75
|
+
`tt install <harness>` (`runInstallCommand`, `src/cli/install-commands.ts:39`) does two things per
|
|
76
|
+
harness: (a) install/refresh the bundled `talking-stick` skill, and (b) clean up stale MCP
|
|
77
|
+
registrations from older releases. `tt install` no longer **adds** MCP servers (README:164).
|
|
78
|
+
|
|
79
|
+
Skill install targets (`resolveSkillTargetPath`, `src/skill-install.ts:42`):
|
|
80
|
+
|
|
81
|
+
- `claude-code` → `~/.claude/skills/talking-stick`
|
|
82
|
+
- `codex` → `~/.codex/skills/talking-stick`
|
|
83
|
+
- `grok` → `<grok config dir>/skills/talking-stick` (default `~/.grok`)
|
|
84
|
+
- `opencode` → `<opencode config dir>/skills/talking-stick` (default `~/.config/opencode`, honors `XDG_CONFIG_HOME`)
|
|
85
|
+
- `gemini` → **special-cased** (`planSkillInstall`, `src/skill-install.ts:80-105`): runs
|
|
86
|
+
`gemini skills link <src> --scope user --consent` (or `gemini skills install ...` with `--copy`).
|
|
87
|
+
The on-disk location it *inspects* is `~/.gemini/skills/talking-stick`.
|
|
88
|
+
|
|
89
|
+
For the four `FILE_SKILL_HARNESSES`, `installSkillDirectory` (`src/skill-install.ts:188`) writes a
|
|
90
|
+
**symlink** (default) or a recursive **copy** (`--copy`) into the proprietary folder. Each harness
|
|
91
|
+
gets its **own physical copy/symlink**. Idempotence is via `inspectInstalledSkill`
|
|
92
|
+
(`src/skill-install.ts:291`): symlink → bundled source = `present`; matching copy digest = `present`.
|
|
93
|
+
|
|
94
|
+
`syncInstalledSkills` (`src/skill-install.ts:161`) silently realigns the four
|
|
95
|
+
`FILE_SKILL_HARNESSES` on human CLI runs (called from `runStartupMaintenance`,
|
|
96
|
+
`src/cli/startup-maintenance.ts:32`). Gemini is excluded from silent sync (README:176, SKILL.md:52).
|
|
97
|
+
|
|
98
|
+
### 2.4 How uninstall / stale cleanup works
|
|
99
|
+
|
|
100
|
+
- `planSkillUninstall` (`src/skill-install.ts:129`) removes the proprietary folder, or for gemini
|
|
101
|
+
runs `gemini skills uninstall talking-stick --scope user`.
|
|
102
|
+
- `planUninstall` (`src/install.ts:274`) removes legacy MCP registrations: `claude mcp remove`,
|
|
103
|
+
`codex mcp remove`, `gemini mcp remove -s user` (`src/install.ts:303`), OpenCode JSON patch.
|
|
104
|
+
Grok is skipped (`src/install.ts:316`).
|
|
105
|
+
- `removeStaleMcpRegistrations` (`src/install-migration.ts:35`) + `runStaleMcpCleanup`
|
|
106
|
+
(`src/update-migration.ts:58`) run on install, uninstall, self-update, and first-run after a
|
|
107
|
+
version change. It is **strict** for OpenCode (only removes the canonical `["tt","mcp"]` shape;
|
|
108
|
+
preserves hand-edited entries) and name-only for the exec harnesses
|
|
109
|
+
(`src/install-migration.ts:18-26`).
|
|
110
|
+
|
|
111
|
+
### 2.5 There is no `~/.agents/skills` concept anywhere yet
|
|
112
|
+
|
|
113
|
+
`grep -rn "\.agents\|agents/skills"` across `src/ tests/ docs/ skills/ README.md` returns **nothing**.
|
|
114
|
+
A shared agents skills directory is entirely net-new. Likewise `antigravity`/`agy` appears nowhere.
|
|
115
|
+
|
|
116
|
+
### 2.5a Codex read-only recon (2026-06-13, `codex:b71174a5`)
|
|
117
|
+
|
|
118
|
+
Folded in from Codex's pre-review recon on this machine:
|
|
119
|
+
|
|
120
|
+
- **`agy` has no `skills` subcommand.** `agy --help` exposes `plugin import/install/link` (a plugin
|
|
121
|
+
system), not `agy skills ...`. → **Do not** model Antigravity as `gemini`-style registry-exec via a
|
|
122
|
+
fake `agy skills`. Antigravity skills are file-based via `~/.agents/skills`. (If a plugin-based path
|
|
123
|
+
is ever wanted, it would be `agy plugin`, but file-based shared install is the primary route.)
|
|
124
|
+
- **Official Antigravity migration guidance:** workspace `.gemini/skills` should move/rename to
|
|
125
|
+
`.agents/skills`. This confirms `.agents/skills` as the convergent convention (project scope; the
|
|
126
|
+
user-scope analogue is `~/.agents/skills`).
|
|
127
|
+
- **Live duplication evidence on this machine:** `~/.agents/skills` exists but has **no** talking-stick
|
|
128
|
+
entry; meanwhile `talking-stick` is currently linked into `~/.claude`, `~/.codex`, `~/.gemini`,
|
|
129
|
+
`~/.grok`, **and** `~/.opencode`. Separately, **both** `~/.opencode/skills` and
|
|
130
|
+
`~/.config/opencode/skills` exist — note our code targets only `~/.config/opencode`
|
|
131
|
+
(`resolveOpencodeConfigDirFromResolved`, `src/install.ts:241`), so an `~/.opencode/skills` copy is
|
|
132
|
+
either user-created or from another tool. This is concrete evidence that multi-location skill state
|
|
133
|
+
already exists and will duplicate once a harness reads both shared and proprietary.
|
|
134
|
+
- **Codex design steer:** make the shared `agents` target **first-class**, and keep harness-specific
|
|
135
|
+
targets only where needed — Claude Code (`~/.claude/skills`, if it does not read `~/.agents/skills`)
|
|
136
|
+
and harness-only extras like the Grok session hook. Antigravity identity from `ANTIGRAVITY_AGENT`
|
|
137
|
+
plus conversation/trajectory IDs and ancestry label `agy`. Recorded as the leading **D1** option
|
|
138
|
+
in §8.
|
|
139
|
+
|
|
140
|
+
### 2.6 Key existing invariant we must preserve
|
|
141
|
+
|
|
142
|
+
The bundled `SKILL.md` **self-gates**: its `description` says to use it only when the workspace
|
|
143
|
+
coordinates with Talking Stick or contains a `.talking-stick/` marker (`skills/talking-stick/SKILL.md:3`,
|
|
144
|
+
lines 16-22). This matters: installing into a **broadly shared** `~/.agents/skills` means every agent
|
|
145
|
+
reading that directory will see the skill. Because the skill self-gates, a broad install is acceptable
|
|
146
|
+
and does not force coordination behavior onto unrelated repos.
|
|
147
|
+
|
|
148
|
+
## 3. Problem statement (the duplication bug we are preventing)
|
|
149
|
+
|
|
150
|
+
If a harness loads skills from **both** a shared `~/.agents/skills/talking-stick` **and** its
|
|
151
|
+
proprietary `~/.<harness>/skills/talking-stick`, and `tt install` writes both, the agent sees the
|
|
152
|
+
`talking-stick` skill **twice**. Consequences:
|
|
153
|
+
|
|
154
|
+
- Two skill entries with the same name → ambiguous/duplicated tool surface.
|
|
155
|
+
- If one location is stale (older bundled version) and the other fresh, the agent may load
|
|
156
|
+
conflicting instructions depending on the harness's precedence rules (which are undefined / vary).
|
|
157
|
+
- Silent sync (`syncInstalledSkills`) keeps re-asserting the proprietary copy, so the duplicate
|
|
158
|
+
never self-heals.
|
|
159
|
+
|
|
160
|
+
Today this does not bite because (as far as the current code assumes) each file harness reads only
|
|
161
|
+
its own proprietary folder. The moment a harness (Antigravity is the immediate case; possibly Codex
|
|
162
|
+
or others later) also reads `~/.agents/skills`, the duplication appears. We want to ship the model
|
|
163
|
+
that prevents it **before** Antigravity lands, and clean up any duplicates older `tt` versions created.
|
|
164
|
+
|
|
165
|
+
## 4. Proposed design
|
|
166
|
+
|
|
167
|
+
### 4.1 Introduce a single harness capability registry
|
|
168
|
+
|
|
169
|
+
Create one authoritative table describing each harness's skill-loading model and config locations,
|
|
170
|
+
and derive the scattered lists from it. Proposed location: `src/harness-registry.ts` (new), or extend
|
|
171
|
+
`src/install.ts`. Shape (illustrative, not final):
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
type SkillLoadingModel =
|
|
175
|
+
| { kind: "shared" } // reads ~/.agents/skills only
|
|
176
|
+
| { kind: "proprietary" } // reads ~/.<harness>/skills only
|
|
177
|
+
| { kind: "shared+proprietary" } // reads both -> install ONCE (prefer shared)
|
|
178
|
+
| { kind: "registry-exec" }; // managed by the harness's own `skills` CLI (legacy gemini)
|
|
179
|
+
|
|
180
|
+
interface HarnessSpec {
|
|
181
|
+
installId: HarnessId; // e.g. "antigravity"
|
|
182
|
+
identityName: HarnessCliHarness; // e.g. "antigravity"
|
|
183
|
+
commandLabels: string[]; // process basenames -> e.g. ["agy", "antigravity"]
|
|
184
|
+
envDetect: (env) => HarnessSignal | null;
|
|
185
|
+
configDir: (resolved) => string; // proprietary config dir (may be unused for shared-only)
|
|
186
|
+
skill: SkillLoadingModel;
|
|
187
|
+
mcpCleanup: "none" | "exec" | "opencode-json";
|
|
188
|
+
deprecated?: boolean;
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The registry becomes the single source of truth. `SUPPORTED_HARNESSES`, `FILE_SKILL_HARNESSES`,
|
|
193
|
+
`HARNESS_COMMAND_MAPPING`, `HarnessCliHarness`, and the instruction aliases are derived from it (or at
|
|
194
|
+
minimum cross-checked by a test that fails if they drift). This directly mitigates the "enumeration
|
|
195
|
+
duplicated across modules" fragility from §2.1 and makes the Antigravity addition and any future
|
|
196
|
+
correction to a harness's skill model a one-line change.
|
|
197
|
+
|
|
198
|
+
> Scope control for the reviewer: a full registry refactor may be larger than the operator wants in
|
|
199
|
+
> one PR. A lighter alternative is to add `antigravity` to the existing lists and add a small
|
|
200
|
+
> `SKILL_LOADING_MODEL: Record<HarnessId, SkillLoadingModel>` map plus a shared-dir resolver, deferring
|
|
201
|
+
> the broader registry consolidation. Flagged as decision **D1** in §8.
|
|
202
|
+
|
|
203
|
+
### 4.2 Shared agents skills directory resolver
|
|
204
|
+
|
|
205
|
+
Add `resolveSharedAgentsSkillsDir(options)` returning `path.join(homeDir, ".agents", "skills")` by
|
|
206
|
+
default. Keep it override-aware (e.g. an `AGENTS_DIR`/`AGENTS_HOME` env var) **only if** such a
|
|
207
|
+
convention is confirmed — otherwise hardcode `~/.agents/skills` and leave a TODO. The skill target
|
|
208
|
+
becomes `<shared>/talking-stick`. (Verification needed — open question **Q2**.)
|
|
209
|
+
|
|
210
|
+
### 4.3 Install algorithm: one physical install per location, with dedup
|
|
211
|
+
|
|
212
|
+
`runInstallCommand` / `planInstallActionsForHarness` change from "one skill action per harness" to:
|
|
213
|
+
|
|
214
|
+
1. Resolve the target harness set (explicit args or `--all` detected).
|
|
215
|
+
2. For each harness, look up its `SkillLoadingModel`:
|
|
216
|
+
- `shared` or `shared+proprietary` → contributes a skill install at `<shared>/talking-stick`.
|
|
217
|
+
- `proprietary` → contributes a skill install at `~/.<harness>/skills/talking-stick`.
|
|
218
|
+
- `registry-exec` (legacy gemini) → no new install (deprecated; see §4.6).
|
|
219
|
+
3. **Deduplicate skill actions by absolute target path** so that, e.g., `tt install --all` with two
|
|
220
|
+
shared-reading harnesses writes `~/.agents/skills/talking-stick` exactly once and reports it once.
|
|
221
|
+
(Today actions run via `Promise.all`, `src/cli/install-commands.ts:57-61`; two parallel writes to
|
|
222
|
+
the same path are individually idempotent but race on the `removeInstalledSkill`→`symlink` window
|
|
223
|
+
in `installSkillDirectory`, `src/skill-install.ts:200-212`. Dedup removes the race and the
|
|
224
|
+
double-report.)
|
|
225
|
+
4. For `shared+proprietary` harnesses, also enqueue a **proprietary-copy cleanup** action (see §4.5)
|
|
226
|
+
so the redundant `~/.<harness>/skills/talking-stick` is removed once the shared install exists.
|
|
227
|
+
|
|
228
|
+
The skill action itself (symlink-or-copy, idempotent inspect) is unchanged; only the **set and
|
|
229
|
+
location** of actions changes. Reuse `installSkillDirectory`/`inspectInstalledSkill` for the shared
|
|
230
|
+
target — they are already path-agnostic.
|
|
231
|
+
|
|
232
|
+
### 4.4 Antigravity specifics
|
|
233
|
+
|
|
234
|
+
- **Detection** (`detectHarnessSignal`, `src/identity.ts:444`): add, ordered before/after Gemini:
|
|
235
|
+
```ts
|
|
236
|
+
if (env.ANTIGRAVITY_AGENT === "1" ||
|
|
237
|
+
nonEmpty(env.ANTIGRAVITY_CONVERSATION_ID) ||
|
|
238
|
+
nonEmpty(env.ANTIGRAVITY_TRAJECTORY_ID)) {
|
|
239
|
+
return {
|
|
240
|
+
harness: "antigravity",
|
|
241
|
+
sessionId: nonEmpty(env.ANTIGRAVITY_CONVERSATION_ID) ?? nonEmpty(env.ANTIGRAVITY_TRAJECTORY_ID),
|
|
242
|
+
pidHint: null
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
Recommend `ANTIGRAVITY_CONVERSATION_ID` as the primary session anchor (stable per conversation);
|
|
247
|
+
`ANTIGRAVITY_TRAJECTORY_ID` is likely finer-grained (per turn/sub-task) and would fragment identity
|
|
248
|
+
if used as the anchor. Decision **D2** / open question **Q3**.
|
|
249
|
+
- **Command mapping** (`HARNESS_COMMAND_MAPPING`, `src/identity.ts:406`): add `agy → antigravity` and
|
|
250
|
+
`antigravity → antigravity` so ancestry detection works when env markers are absent (consistent with
|
|
251
|
+
how Grok is detected by ancestry).
|
|
252
|
+
- **Identity prefix / display name**: recommend `antigravity` (matches the env-marker family and reads
|
|
253
|
+
clearly in `agent_id`s like `antigravity:ab12cd34`). The binary stays `agy`. Decision **D2**.
|
|
254
|
+
- **Skill loading model**: `shared` (reads `~/.agents/skills`). **Confirmed file-based** by Codex
|
|
255
|
+
recon (§2.5a): `agy` has no `skills` subcommand, and Antigravity migration guidance routes skills to
|
|
256
|
+
`.agents/skills`. Install target therefore `~/.agents/skills/talking-stick`, file copy/symlink —
|
|
257
|
+
**not** an exec. (A plugin path `agy plugin import/install/link` exists but is not the route here.)
|
|
258
|
+
Still verify *which other* harnesses share that dir (open question **Q1**).
|
|
259
|
+
- **MCP cleanup**: `none` (like Grok). `agy` has no `mcp`/`skills` registry surface we use, and `tt`
|
|
260
|
+
no longer adds MCP servers.
|
|
261
|
+
- **`detectHarness`** (`src/install.ts:532`, used by `--all`): add an `antigravity` branch. Use
|
|
262
|
+
`which agy` as the **strong** presence signal. Do **not** key presence on `~/.agents/skills` alone —
|
|
263
|
+
it is shared and may exist for unrelated reasons (it already exists empty on this machine, §2.5a), so
|
|
264
|
+
it would over-claim Antigravity under `--all`. Antigravity has no confirmed proprietary config dir
|
|
265
|
+
(**Q4**), so absent `agy` on PATH, treat as not-detected.
|
|
266
|
+
- **Instruction routing**: add `antigravity`/`agy` to `HARNESS_ALIASES` (`src/instructions.ts:95`),
|
|
267
|
+
add `antigravity` to `InstructionHarness`, add a `## Antigravity` section to
|
|
268
|
+
`DEFAULT_INSTRUCTIONS_MARKDOWN`, and update the prose line at `src/instructions.ts:68`.
|
|
269
|
+
|
|
270
|
+
### 4.5 Migration / cleanup of existing installs
|
|
271
|
+
|
|
272
|
+
Three classes of existing state to handle on `tt install`, `tt uninstall`, `tt self-update`, and
|
|
273
|
+
first-run-after-version-change (reuse the `runStaleMcpCleanup` plumbing in `src/update-migration.ts`):
|
|
274
|
+
|
|
275
|
+
1. **Redundant proprietary copies for shared-reading harnesses.** When a harness's model is
|
|
276
|
+
`shared`/`shared+proprietary` and a tt-managed `talking-stick` skill exists in its **proprietary**
|
|
277
|
+
folder, remove the proprietary copy once the shared install exists. **Safety gate (strict, mirrors
|
|
278
|
+
the OpenCode MCP cleanup philosophy):** only remove when the proprietary entry is clearly
|
|
279
|
+
tt-managed — a **symlink** whose realpath resolves to the bundled skill source, OR a directory whose
|
|
280
|
+
digest matches a **known-tt-bundled** digest (current or a recorded set of prior-release digests).
|
|
281
|
+
A `talking-stick` directory that is neither (i.e. hand-authored or unknown) is **preserved** and
|
|
282
|
+
reported, never deleted. This avoids nuking a user's own skill or a copy a still-proprietary-only
|
|
283
|
+
harness genuinely needs.
|
|
284
|
+
- Open question **Q5**: maintaining a set of prior-release bundled digests is the only robust way
|
|
285
|
+
to recognize a *stale tt copy*. Alternative: only auto-remove **symlinks** (cheap, unambiguous)
|
|
286
|
+
and leave copies to a `--prune-duplicates` opt-in. Recommend symlink-only auto-removal + opt-in
|
|
287
|
+
prune for copies, to stay conservative.
|
|
288
|
+
2. **Gemini deprecation cleanup.** See §4.6.
|
|
289
|
+
3. **Audit.** Every removal appends a JSONL audit entry (extend `install-audit.ts` reasons/targets to
|
|
290
|
+
cover skill-dir cleanups, not just MCP). The existing audit currently only models MCP cleanup
|
|
291
|
+
(`AuditAction`, `src/install-migration.ts`); a parallel "skill cleanup" audit path or a generalized
|
|
292
|
+
action enum is needed. Decision **D3**.
|
|
293
|
+
|
|
294
|
+
`syncInstalledSkills` (silent human-CLI sync) must also be updated to (a) sync the shared location for
|
|
295
|
+
shared-reading harnesses, and (b) **stop re-creating** proprietary copies for shared-reading harnesses
|
|
296
|
+
(otherwise it re-introduces the duplicate the migration just removed). This is the most important
|
|
297
|
+
behavioral edit in the silent path.
|
|
298
|
+
|
|
299
|
+
### 4.6 Gemini deprecation
|
|
300
|
+
|
|
301
|
+
The operator states Gemini CLI support is being deprecated/replaced by Antigravity. Proposed handling
|
|
302
|
+
(conservative, non-stranding):
|
|
303
|
+
|
|
304
|
+
- **Keep identity detection** for `GEMINI_CLI=1` and `gemini` ancestry so any still-running Gemini
|
|
305
|
+
session keeps a stable identity and can coordinate during the transition. (Decision **D4**: fully
|
|
306
|
+
drop vs keep detection. Recommend keep for now.)
|
|
307
|
+
- **Stop installing** the Gemini skill: `gemini` is dropped from default `--all` install targets and
|
|
308
|
+
from any "install the skill" path. `tt install gemini` prints a deprecation notice and performs
|
|
309
|
+
cleanup-only (see below) rather than `gemini skills link`.
|
|
310
|
+
- **Active cleanup on update/first-run:** best-effort `gemini skills uninstall talking-stick --scope user`
|
|
311
|
+
and `gemini mcp remove -s user talking-stick`, guarded by `which gemini` / `skipMissing` so machines
|
|
312
|
+
without Gemini are silent no-ops. This removes the old registry skill so it cannot duplicate the new
|
|
313
|
+
Antigravity/shared skill.
|
|
314
|
+
- **Recognize-but-deprecate the token:** keep `gemini` accepted by `parseHarnessList` and the
|
|
315
|
+
`## Gemini` alias in instruction parsing (so existing project instruction files with `## Gemini`
|
|
316
|
+
sections still extract) but mark it deprecated. Replace the `## Gemini` block in the **default**
|
|
317
|
+
instructions template with `## Antigravity`.
|
|
318
|
+
- Decision **D5**: timeline — do we remove Gemini entirely in a later release, or keep the deprecated
|
|
319
|
+
shim indefinitely? Recommend: ship deprecation + cleanup now, schedule full removal for a later
|
|
320
|
+
major.
|
|
321
|
+
|
|
322
|
+
### 4.7 Uninstall semantics for the shared dir
|
|
323
|
+
|
|
324
|
+
`tt uninstall` must remove only `<shared>/talking-stick`, **never** the whole `~/.agents/skills`
|
|
325
|
+
directory (it is shared with other tools). After removing the subdir, if `~/.agents/skills` is now
|
|
326
|
+
empty, leaving it is fine; do not attempt to remove the parent. Mirror the existing
|
|
327
|
+
`removeInstalledSkill` symlink-vs-dir handling (`src/skill-install.ts:324`).
|
|
328
|
+
|
|
329
|
+
## 5. CLI / API surface changes
|
|
330
|
+
|
|
331
|
+
- `tt install antigravity` → writes `~/.agents/skills/talking-stick` (shared model).
|
|
332
|
+
- `tt install --all` → dedups shared targets; one shared write covers all shared-reading harnesses.
|
|
333
|
+
- `tt install gemini` → deprecation notice + cleanup-only (no new skill).
|
|
334
|
+
- `tt uninstall antigravity` → removes `<shared>/talking-stick` only.
|
|
335
|
+
- Help text (`src/cli/output.ts:204`) and README enumerations updated to
|
|
336
|
+
`claude|codex|antigravity|grok|opencode` with `gemini` noted as deprecated.
|
|
337
|
+
- New `SkillLoadingModel`/registry exports from `src/skill-install.ts` (or new module) consumed by
|
|
338
|
+
`install-commands.ts`.
|
|
339
|
+
- (Optional) `tt install --prune-duplicates` opt-in to remove tt-managed proprietary **copies** that
|
|
340
|
+
the conservative auto-cleanup leaves in place (see **Q5**).
|
|
341
|
+
|
|
342
|
+
No new MCP behavior; `tt install` still does not add MCP servers.
|
|
343
|
+
|
|
344
|
+
## 6. Tests to add / update
|
|
345
|
+
|
|
346
|
+
Existing suites that reference gemini or harness lists and will need updates:
|
|
347
|
+
`tests/identity.test.ts`, `tests/install.test.ts`, `tests/skill-install.test.ts`,
|
|
348
|
+
`tests/install-commands.test.ts`, `tests/install-migration.test.ts`, `tests/instructions.test.ts`,
|
|
349
|
+
`tests/cli.test.ts`, `tests/talking-stick.test.ts`, `tests/oob-substrate.test.ts`, `tests/notes.test.ts`.
|
|
350
|
+
|
|
351
|
+
New coverage:
|
|
352
|
+
|
|
353
|
+
1. **Antigravity detection** — `detectHarnessSignal` returns `antigravity` for `ANTIGRAVITY_AGENT=1`,
|
|
354
|
+
for `ANTIGRAVITY_CONVERSATION_ID` only, and for `ANTIGRAVITY_TRAJECTORY_ID` only; session anchor is
|
|
355
|
+
`CONVERSATION_ID` when both present; `agy` ancestry detection when env markers absent.
|
|
356
|
+
2. **Shared skill install** — `tt install antigravity` writes a symlink/copy at
|
|
357
|
+
`<home>/.agents/skills/talking-stick`; idempotent re-run reports `already_present`.
|
|
358
|
+
3. **Dedup** — `tt install --all` with ≥2 shared-reading harnesses produces exactly one shared skill
|
|
359
|
+
action / one report line for `~/.agents/skills/talking-stick`; no race/`ENOENT` flake.
|
|
360
|
+
4. **Proprietary-copy migration** — given a pre-existing tt-managed symlink at
|
|
361
|
+
`~/.codex/skills/talking-stick` (only if Codex's model becomes shared+proprietary — gate on the
|
|
362
|
+
verified model), migration removes it once the shared install exists; a **hand-authored** dir at the
|
|
363
|
+
same path is **preserved** and reported.
|
|
364
|
+
5. **Gemini deprecation** — `tt install gemini` does not call `gemini skills link`; update/first-run
|
|
365
|
+
issues best-effort `gemini skills uninstall` + `gemini mcp remove`; both are silent no-ops when
|
|
366
|
+
`which gemini` is null (`skipMissing`).
|
|
367
|
+
6. **Uninstall** — `tt uninstall antigravity` removes only the `talking-stick` subdir, never the
|
|
368
|
+
`~/.agents/skills` parent.
|
|
369
|
+
7. **Instructions** — `## Antigravity` extracted for antigravity identity; legacy `## Gemini` sections
|
|
370
|
+
still extract under the deprecated alias; `--harness antigravity` accepted; default template shows
|
|
371
|
+
Antigravity not Gemini.
|
|
372
|
+
8. **Registry/lists in sync** — a guard test asserting the derived lists
|
|
373
|
+
(`SUPPORTED_HARNESSES`, `FILE_SKILL_HARNESSES`, command mapping, instruction aliases) match the
|
|
374
|
+
registry, so future drift fails loudly.
|
|
375
|
+
|
|
376
|
+
Use the existing install-test patterns: injected `homeDir`, `pathExists`, `readFile`, `writeFile`,
|
|
377
|
+
`run`, `which` hooks (`InstallerHooks`, `src/install.ts:29`) and `TALKING_STICK_DATA_DIR` temp dirs
|
|
378
|
+
(CLAUDE.md). No real `~/.agents` or `~/.gemini` writes in tests.
|
|
379
|
+
|
|
380
|
+
## 7. Docs to update
|
|
381
|
+
|
|
382
|
+
- `README.md`: harness list (line 5), "How installation works per harness" (lines 162-176), identity
|
|
383
|
+
markers (lines 220), instructions `--harness` enumeration (line 193), command reference (203-204).
|
|
384
|
+
Document the shared `~/.agents/skills` model, the one-install-per-location rule, and Gemini
|
|
385
|
+
deprecation.
|
|
386
|
+
- `skills/talking-stick/SKILL.md`: description harness list (line 3) and the silent-sync note
|
|
387
|
+
(line 52) — replace Gemini with Antigravity, mention shared skills directory.
|
|
388
|
+
- `CLAUDE.md` "Runtime & Dogfooding Notes": the identity-markers bullet and the
|
|
389
|
+
`~/.claude/skills`/`~/.grok/skills` symlink bullet need an Antigravity + `~/.agents/skills` line.
|
|
390
|
+
- `docs/releases/<next>.md` + `CHANGELOG.md`: new entry.
|
|
391
|
+
- This file moves draft → converged once Codex review lands.
|
|
392
|
+
|
|
393
|
+
## 8. Decisions for reviewer (recommendations in **bold**)
|
|
394
|
+
|
|
395
|
+
- **D1 — Shared-first vs per-harness model.** Two framings of the same trim:
|
|
396
|
+
- *(1a) Codex's shared-first (leading):* treat the shared `~/.agents/skills` target as first-class
|
|
397
|
+
and the default for every harness that reads it; keep harness-specific skill targets only where a
|
|
398
|
+
harness does **not** read shared (Claude Code is the likely holdout via `~/.claude/skills`), plus
|
|
399
|
+
harness-only extras (Grok session hook). Fewest physical installs, smallest duplication surface.
|
|
400
|
+
- *(1b) Per-harness model map:* each harness carries a `SkillLoadingModel`
|
|
401
|
+
(`shared`/`proprietary`/`shared+proprietary`/`registry-exec`); the installer derives locations from
|
|
402
|
+
it. More explicit, tolerates a messy reality where harnesses differ.
|
|
403
|
+
These converge in code (1a is 1b with most harnesses set to `shared`). **Recommend implementing the
|
|
404
|
+
1b map (it is the honest data model) but defaulting most harnesses to `shared` per 1a once Q1
|
|
405
|
+
confirms who reads the dir.** Plus a drift-guard test. Defer a full `src/harness-registry.ts`
|
|
406
|
+
consolidation unless the reviewer/operator wants the bigger refactor in this PR.
|
|
407
|
+
- **D2 — Antigravity identity:** prefix `antigravity` (display) with binary label `agy`. **Recommend
|
|
408
|
+
`antigravity` prefix.**
|
|
409
|
+
- **D3 — Audit model:** generalize `install-audit` to cover skill-dir cleanup vs add a parallel skill
|
|
410
|
+
audit path. **Recommend generalizing the action enum.**
|
|
411
|
+
- **D4 — Gemini detection:** keep vs drop. **Recommend keep detection, drop install.**
|
|
412
|
+
- **D5 — Gemini removal timeline:** **Recommend deprecate+cleanup now, full removal in a later major.**
|
|
413
|
+
|
|
414
|
+
## 9. Risks
|
|
415
|
+
|
|
416
|
+
1. **Unverified `~/.agents/skills` adoption (highest).** The entire trim hinges on *which* harnesses
|
|
417
|
+
actually read `~/.agents/skills` today. Wrong model → either the skill is not loaded (installed only
|
|
418
|
+
to shared, but harness reads only proprietary) or duplicates persist (installed to both). Mitigation:
|
|
419
|
+
verify per harness (Q1), keep the model in one table, ship conservative cleanup (symlink-only
|
|
420
|
+
auto-removal).
|
|
421
|
+
2. **Aggressive proprietary cleanup deletes user content.** A `talking-stick` dir that is not
|
|
422
|
+
tt-managed could be a user's own skill. Mitigation: strict tt-managed gate (symlink→bundled, or
|
|
423
|
+
known-digest), preserve-and-report otherwise — mirrors the strict OpenCode MCP-cleanup precedent.
|
|
424
|
+
3. **Shared-dir blast radius.** Installing into `~/.agents/skills` exposes the skill to every agent
|
|
425
|
+
reading that dir, including in non-coordinating repos. Mitigated by the skill's self-gating
|
|
426
|
+
description (§2.6), but worth an explicit note and operator sign-off.
|
|
427
|
+
4. **Uninstall over-reach.** Removing the shared parent dir would affect other tools. Mitigation:
|
|
428
|
+
only ever remove the `talking-stick` subdir.
|
|
429
|
+
5. **Stranding a live Gemini.** Cutting Gemini detection mid-session would drop a running agent out of
|
|
430
|
+
coordination. Mitigation: keep detection, only stop installing (D4).
|
|
431
|
+
6. **Antigravity unknowns.** Config dir, whether `agy` has `skills`/`mcp` subcommands, and the right
|
|
432
|
+
session anchor are not confirmed (Q3/Q4). Wrong guesses are low-blast (detection/identity only) but
|
|
433
|
+
could pick a poor session granularity.
|
|
434
|
+
7. **Dedup race.** Parallel `Promise.all` install of two shared-reading harnesses both hitting
|
|
435
|
+
`installSkillDirectory` on the same path can `ENOENT`-flake in the remove→symlink window. Mitigation:
|
|
436
|
+
dedup actions by path before running (§4.3).
|
|
437
|
+
8. **List drift.** Harness enumeration lives in ~7 places; missing one (e.g. `HARNESS_COMMAND_MAPPING`)
|
|
438
|
+
yields silent mis-detection. Mitigation: registry + drift-guard test (§6.8).
|
|
439
|
+
9. **Windows.** Shared-dir symlink uses `junction` like existing installs; confirm `~/.agents` parent
|
|
440
|
+
creation and junction semantics on win32 (existing code already branches, `src/skill-install.ts:206`).
|
|
441
|
+
|
|
442
|
+
## 10. Open questions (for Codex review + operator)
|
|
443
|
+
|
|
444
|
+
- **Q1 (still blocking):** Exactly which harnesses read `~/.agents/skills` today — Antigravity is
|
|
445
|
+
confirmed (§2.5a); do Codex / Gemini / OpenCode / Grok also read it, and does Claude Code? This
|
|
446
|
+
determines each harness's `SkillLoadingModel`, the shared-first default (D1/1a), and the migration
|
|
447
|
+
set. Needs per-harness confirmation.
|
|
448
|
+
- **Q2 (partly resolved):** `.agents/skills` confirmed as the convention (§2.5a); the user-scope path
|
|
449
|
+
is `~/.agents/skills` and it already exists on this machine. Still confirm: env override
|
|
450
|
+
(`AGENTS_DIR`/`AGENTS_HOME`/XDG-style)? Nesting as `<dir>/<skill-name>/SKILL.md` like the proprietary
|
|
451
|
+
folders (assumed yes)?
|
|
452
|
+
- **Q3:** Antigravity session anchor — `ANTIGRAVITY_CONVERSATION_ID` vs `ANTIGRAVITY_TRAJECTORY_ID`.
|
|
453
|
+
What is each one's lifetime/granularity? (Recommend CONVERSATION_ID; see D2.)
|
|
454
|
+
- **Q4 (resolved):** `agy` has **no** `skills`/`mcp` subcommands (it has `plugin import/install/link`).
|
|
455
|
+
Antigravity is file-based via `~/.agents/skills`. No confirmed proprietary config dir — so
|
|
456
|
+
`detectHarness` presence keys on `which agy`, not a config dir.
|
|
457
|
+
- **Q5:** Proprietary-copy cleanup — auto-remove only symlinks (conservative) and gate copy removal
|
|
458
|
+
behind `--prune-duplicates`, or maintain prior-release bundled digests to recognize stale tt copies?
|
|
459
|
+
- **Q6:** Should shared-skill install be the **default** for shared-reading harnesses, or opt-in for
|
|
460
|
+
one release while we observe? (Affects rollout risk.)
|
|
461
|
+
- **Q7:** Gemini removal timeline (D5) and whether `--all` should auto-target Antigravity purely from
|
|
462
|
+
`which agy` vs requiring an explicit token.
|
|
463
|
+
- **Q8 (new, from §2.5a):** OpenCode has **both** `~/.opencode/skills` and `~/.config/opencode/skills`
|
|
464
|
+
on this machine, but `tt` only manages `~/.config/opencode`. Should the OpenCode model account for
|
|
465
|
+
the `~/.opencode` location (read it? clean a stale tt copy there?), or is `~/.opencode/skills`
|
|
466
|
+
out of scope (user/other-tool owned)? Relevant to whether OpenCode is `shared`, `proprietary`, or
|
|
467
|
+
`shared+proprietary`.
|
|
468
|
+
|
|
469
|
+
## 11. Codex adversarial review (2026-06-13)
|
|
470
|
+
|
|
471
|
+
### 11.1 Verdict
|
|
472
|
+
|
|
473
|
+
The draft has the right core direction: **one install per physical skill location, with a
|
|
474
|
+
per-harness loading model, and no fake `agy skills` integration.** The implementation should not
|
|
475
|
+
start with a broad harness-registry refactor, though. Start with a narrower `SkillTargetSpec` map
|
|
476
|
+
that resolves install targets and duplicate-cleanup targets. A full registry can follow once the
|
|
477
|
+
model is proven.
|
|
478
|
+
|
|
479
|
+
The main correction is that Q1 is now partly answered by live inspection:
|
|
480
|
+
|
|
481
|
+
- **Codex** exposes both `/Users/wojtek/.codex/skills` and `/Users/wojtek/.agents/skills` in
|
|
482
|
+
`codex debug prompt-input`.
|
|
483
|
+
- **Grok** exposes `/Users/wojtek/.grok/skills`, `/Users/wojtek/.agents/skills`, and
|
|
484
|
+
`/Users/wojtek/.claude/skills` in `grok inspect --json`.
|
|
485
|
+
- **OpenCode** exposes `/Users/wojtek/.agents/skills`, `/Users/wojtek/.config/opencode/skills`, and
|
|
486
|
+
`/Users/wojtek/.opencode/skills` in `opencode debug skill`.
|
|
487
|
+
- **Claude Code** is still only locally confirmed at `/Users/wojtek/.claude/skills`; no live evidence
|
|
488
|
+
yet that it reads `/Users/wojtek/.agents/skills`.
|
|
489
|
+
- **Antigravity** docs and migration guidance point to `.agents/skills`, and `agy` has no `skills`
|
|
490
|
+
subcommand. However, local state also has `/Users/wojtek/.gemini/antigravity/skills`, so the
|
|
491
|
+
implementation should include a live `agy` discovery experiment before deleting any Antigravity-
|
|
492
|
+
specific or Gemini-era skill copy.
|
|
493
|
+
|
|
494
|
+
### 11.2 Required changes before implementation
|
|
495
|
+
|
|
496
|
+
1. **Make the first implementation map-driven, not registry-driven.** Add a focused map like:
|
|
497
|
+
`installId -> { primarySkillTarget, duplicateSkillTargets, extras, deprecated }`. Let
|
|
498
|
+
`SUPPORTED_HARNESSES` remain explicit for now, backed by drift tests. This avoids turning a
|
|
499
|
+
harness-path bug fix into a broad architecture change.
|
|
500
|
+
|
|
501
|
+
2. **Treat shared install as primary for Codex, Grok, OpenCode, and Antigravity only after their live
|
|
502
|
+
loader is verified.** Based on local evidence, Codex/Grok/OpenCode all read `~/.agents/skills`.
|
|
503
|
+
Claude should stay proprietary unless proven otherwise. Grok still needs the proprietary hook
|
|
504
|
+
install at `~/.grok/hooks/talking-stick-session.json`; only the skill moves to shared.
|
|
505
|
+
|
|
506
|
+
3. **OpenCode cleanup is more urgent than the draft implies.** A stale
|
|
507
|
+
`~/.opencode/skills/talking-stick` can shadow both `~/.config/opencode/skills/talking-stick` and
|
|
508
|
+
`~/.agents/skills/talking-stick`. If shared becomes primary, the cleanup set for OpenCode must
|
|
509
|
+
include both proprietary roots:
|
|
510
|
+
`~/.opencode/skills/talking-stick` and `<XDG_CONFIG_HOME|~/.config>/opencode/skills/talking-stick`.
|
|
511
|
+
Auto-remove only if the entry is a symlink to the bundled skill. Preserve copies or unknown dirs
|
|
512
|
+
unless an explicit prune flag is added.
|
|
513
|
+
|
|
514
|
+
4. **Use symlink-only automatic duplicate removal for v1.** Do not maintain historical bundled
|
|
515
|
+
digests in the first pass. A digest table sounds precise but becomes release-state bookkeeping
|
|
516
|
+
and still cannot prove user intent. For v1, auto-remove only symlinks that resolve to the bundled
|
|
517
|
+
`skills/talking-stick` source. Report copied/unknown duplicate directories as preserved.
|
|
518
|
+
|
|
519
|
+
5. **Sequence install and cleanup deterministically.** Install or verify the shared target first.
|
|
520
|
+
Only then remove tt-managed proprietary duplicates. Do not run same-path or related cleanup actions
|
|
521
|
+
in the existing per-harness `Promise.all` path. Dedup by real target path before execution.
|
|
522
|
+
|
|
523
|
+
6. **Keep Gemini identity, but make install behavior unmistakable.** `tt install gemini` should print
|
|
524
|
+
a deprecation message that points to `tt install antigravity`, then run cleanup-only if possible.
|
|
525
|
+
`tt install --all` should not select Gemini merely because `~/.gemini` exists; it should prefer
|
|
526
|
+
Antigravity when `agy` is present.
|
|
527
|
+
|
|
528
|
+
7. **Do not use `~/.agents/skills` existence as harness detection.** It is a shared substrate. Use
|
|
529
|
+
`which agy` for Antigravity install detection, and runtime env/ancestry for identity.
|
|
530
|
+
|
|
531
|
+
8. **Add an explicit manual/live verification checklist before coding cleanup.** The plan should require
|
|
532
|
+
commands equivalent to:
|
|
533
|
+
`codex debug prompt-input`, `grok inspect --json`, `opencode debug skill`, and an `agy` discovery
|
|
534
|
+
check. Unit tests should not depend on those commands, but the implementation branch should record
|
|
535
|
+
the observed loader paths in the final handoff.
|
|
536
|
+
|
|
537
|
+
### 11.3 Revised loading model recommendation
|
|
538
|
+
|
|
539
|
+
Initial `SkillLoadingModel` values for implementation:
|
|
540
|
+
|
|
541
|
+
- `claude-code`: `proprietary`, target `~/.claude/skills/talking-stick`.
|
|
542
|
+
- `codex`: `shared+proprietary`, primary `~/.agents/skills/talking-stick`, duplicate cleanup
|
|
543
|
+
`~/.codex/skills/talking-stick`.
|
|
544
|
+
- `antigravity`: `shared`, primary `~/.agents/skills/talking-stick`; keep an open verification item
|
|
545
|
+
for any `~/.gemini/antigravity/skills` compatibility path.
|
|
546
|
+
- `grok`: `shared+proprietary`, primary `~/.agents/skills/talking-stick`, duplicate cleanup
|
|
547
|
+
`~/.grok/skills/talking-stick`, plus keep the Grok session hook install in `~/.grok/hooks`.
|
|
548
|
+
- `opencode`: `shared+proprietary`, primary `~/.agents/skills/talking-stick`, duplicate cleanup
|
|
549
|
+
for both `~/.opencode/skills/talking-stick` and
|
|
550
|
+
`<XDG_CONFIG_HOME|~/.config>/opencode/skills/talking-stick`.
|
|
551
|
+
- `gemini`: deprecated, identity-only plus cleanup-only.
|
|
552
|
+
|
|
553
|
+
This is intentionally conservative: it removes duplicate `talking-stick` entries while preserving
|
|
554
|
+
loader-specific extras and avoiding destructive cleanup of unknown copies.
|
|
555
|
+
|
|
556
|
+
### 11.4 Additional tests to add
|
|
557
|
+
|
|
558
|
+
Add or revise these specific tests beyond the draft list:
|
|
559
|
+
|
|
560
|
+
1. `tt install --all` with Codex, Grok, OpenCode, and Antigravity detected plans exactly one shared
|
|
561
|
+
skill install action and no proprietary skill install actions for those harnesses.
|
|
562
|
+
2. OpenCode duplicate cleanup considers both legacy proprietary roots and removes only symlinks to the
|
|
563
|
+
bundled source.
|
|
564
|
+
3. A preserved unknown proprietary duplicate is reported but does not fail install.
|
|
565
|
+
4. `syncInstalledSkills` updates the shared target and does not recreate proprietary duplicates for
|
|
566
|
+
shared-reading harnesses.
|
|
567
|
+
5. `tt install gemini --print` shows cleanup/deprecation actions, not `gemini skills link`.
|
|
568
|
+
6. `detectHarness("antigravity")` is true only from `agy` on PATH or an explicit Antigravity config
|
|
569
|
+
signal if later discovered, not from `~/.agents/skills`.
|
|
570
|
+
|
|
571
|
+
### 11.5 Convergence questions for Claude/operator
|
|
572
|
+
|
|
573
|
+
1. Should `tt install --all` install `~/.agents/skills/talking-stick` when only Codex/Grok/OpenCode are
|
|
574
|
+
detected but `agy` is not installed? Codex says yes if any shared-reading harness is detected,
|
|
575
|
+
because shared is now their primary target.
|
|
576
|
+
2. Should `tt uninstall codex` remove shared `~/.agents/skills/talking-stick` if Grok/OpenCode also
|
|
577
|
+
use it? Codex says no: uninstall must be target-aware. Removing the shared skill should happen only
|
|
578
|
+
when uninstalling the last selected shared-reading harness or via an explicit `tt uninstall agents`
|
|
579
|
+
style target. This needs a concrete CLI rule before implementation.
|
|
580
|
+
3. Is symlink-only duplicate pruning enough for this release? Codex says yes; copied unknown dirs can be
|
|
581
|
+
reported with a next command or manual path.
|
|
582
|
+
|
|
583
|
+
## 12. Convergence (Claude, 2026-06-13) — AUTHORITATIVE
|
|
584
|
+
|
|
585
|
+
This section supersedes the recommendations in §8/§10/§11 where they differ. Codex's review (§11) is
|
|
586
|
+
accepted almost entirely. Two new pieces of independent verification close the last gaps.
|
|
587
|
+
|
|
588
|
+
### 12.1 New verification done this pass (Claude, `claude:529d0454`)
|
|
589
|
+
|
|
590
|
+
- **`agy` has no `skills`/`mcp` surface — re-confirmed locally.** `agy --help` subcommands are exactly:
|
|
591
|
+
`changelog`, `help`, `install`, `models`, `plugin`/`plugins`, `update`. No `skills`, no `mcp`.
|
|
592
|
+
→ Antigravity is file-based via `~/.agents/skills`; presence detection keys on `which agy`. **Q4 closed.**
|
|
593
|
+
- **Claude Code does NOT read `~/.agents/skills` — authoritatively confirmed.** Per official docs
|
|
594
|
+
(https://code.claude.com/docs/en/skills.md#where-skills-live), Claude Code's only skill discovery
|
|
595
|
+
locations are `~/.claude/skills/` (personal), `.claude/skills/` (project), plugin-bundled skills, and
|
|
596
|
+
`--add-dir` `.claude/skills` subdirs. There is **no** `~/.agents/skills` support. → Installing into
|
|
597
|
+
the shared dir cannot create a duplicate for Claude. **Claude Code stays `proprietary`. Q1 closed for Claude.**
|
|
598
|
+
- **All current proprietary installs are symlinks to the bundled source.** Verified `talking-stick` is a
|
|
599
|
+
symlink (not a copy) in `~/.claude`, `~/.codex`, `~/.grok`, `~/.opencode`, `~/.config/opencode`, and
|
|
600
|
+
`~/.gemini`, every one resolving to `dev/ai/talking-stick/skills/talking-stick`. → The conservative
|
|
601
|
+
**symlink-only auto-prune fully covers the real migration set on this machine** (no copies to leave behind).
|
|
602
|
+
- `~/.agents/skills` exists and is populated by *other* tools (agent-browser, clawdapus-cli, cmux-browser,
|
|
603
|
+
mcporter, microsoft-foundry, openclaw-cli-reference) but has **no** talking-stick entry yet — confirms
|
|
604
|
+
the shared dir is a real shared substrate (do not treat its existence as Antigravity detection; **Q8/D-detect**).
|
|
605
|
+
- Note: `~/.gemini/antigravity/skills` was **not** present on re-check (only `~/.gemini/skills/talking-stick`
|
|
606
|
+
symlink exists). The Antigravity-compat verification item from §11.1 stays as a live implementation check
|
|
607
|
+
but there is no `~/.gemini/antigravity` copy to migrate here today.
|
|
608
|
+
|
|
609
|
+
### 12.2 Decisions — resolved
|
|
610
|
+
|
|
611
|
+
- **D1 — model shape:** Implement the **map-driven `SkillLoadingModel`** (§11.2.1), *not* a broad
|
|
612
|
+
`src/harness-registry.ts` refactor in this PR. A focused
|
|
613
|
+
`Record<HarnessId, { model, primaryTarget, duplicateTargets[], extras[], deprecated }>` plus a
|
|
614
|
+
**drift-guard test** that asserts the existing scattered lists agree with it. Full registry
|
|
615
|
+
consolidation is explicitly deferred to a later PR.
|
|
616
|
+
- **D2 — Antigravity identity:** prefix/display = **`antigravity`**, binary/command label = **`agy`**
|
|
617
|
+
(also map `antigravity` as a command label). Session anchor = **`ANTIGRAVITY_CONVERSATION_ID`**, falling
|
|
618
|
+
back to `ANTIGRAVITY_TRAJECTORY_ID`, then ancestry. **Q3 resolved** this way; trajectory is presumed
|
|
619
|
+
finer-grained and would fragment identity.
|
|
620
|
+
- **D3 — audit:** **generalize** the `install-audit`/`AuditAction` enum to cover skill-dir cleanup
|
|
621
|
+
(reasons: `skill_duplicate_symlink`, `gemini_deprecated_skill`, plus the existing MCP reasons), so every
|
|
622
|
+
skill removal is journaled the same way MCP cleanups already are.
|
|
623
|
+
- **D4 — Gemini detection:** **keep** identity detection (`GEMINI_CLI=1` + `gemini` ancestry); **drop**
|
|
624
|
+
the install. `tt install gemini` becomes deprecation-notice + cleanup-only.
|
|
625
|
+
- **D5 — Gemini removal timeline:** ship **deprecate + cleanup now**; schedule full identity/token removal
|
|
626
|
+
for a later major. Keep `gemini` accepted by `parseHarnessList` and the `## Gemini` instruction alias
|
|
627
|
+
(so existing project instruction files still extract), but replace `## Gemini` in the **default** template
|
|
628
|
+
with `## Antigravity`.
|
|
629
|
+
- **D6 (new) — shared install is default, not opt-in (Q6).** Shared-reading harnesses install to
|
|
630
|
+
`~/.agents/skills/talking-stick` immediately on ship. Low risk because (a) the bundled `SKILL.md`
|
|
631
|
+
self-gates (§2.6) so a broad install does not force behavior, and (b) we clean the duplicates in the
|
|
632
|
+
same release. No staged opt-in.
|
|
633
|
+
|
|
634
|
+
### 12.3 Final per-harness loading model (authoritative)
|
|
635
|
+
|
|
636
|
+
| installId | identity | command labels | model | primary target | duplicate-cleanup targets (symlink-only auto-prune) | extras / notes |
|
|
637
|
+
|--------------|------------|------------------------|---------------------|--------------------------------------|---------------------------------------------------------------------------------------|----------------|
|
|
638
|
+
| claude-code | claude | claude, claude-code | `proprietary` | `~/.claude/skills/talking-stick` | — | docs-confirmed: does not read shared |
|
|
639
|
+
| codex | codex | codex | `shared+proprietary`| `~/.agents/skills/talking-stick` | `~/.codex/skills/talking-stick` | |
|
|
640
|
+
| antigravity | antigravity| agy, antigravity | `shared` | `~/.agents/skills/talking-stick` | — | presence = `which agy`; identity env above; live-verify any `~/.gemini/antigravity` compat path |
|
|
641
|
+
| grok | grok | grok | `shared+proprietary`| `~/.agents/skills/talking-stick` | `~/.grok/skills/talking-stick` | **keep** Grok session hook at `~/.grok/hooks/talking-stick-session.json` (extra, not pruned) |
|
|
642
|
+
| opencode | opencode | opencode | `shared+proprietary`| `~/.agents/skills/talking-stick` | `~/.opencode/skills/talking-stick` **and** `<XDG_CONFIG_HOME|~/.config>/opencode/skills/talking-stick` | both legacy roots cleaned |
|
|
643
|
+
| gemini | gemini | gemini | `deprecated` | — (no install) | `~/.gemini/skills/talking-stick` (symlink) + best-effort `gemini skills uninstall` / `gemini mcp remove` | identity kept; install cleanup-only |
|
|
644
|
+
|
|
645
|
+
Shared resolver: `resolveSharedAgentsSkillsDir(opts) = path.join(homeDir, ".agents", "skills")`, using the
|
|
646
|
+
same injectable `homeDir` hook the other resolvers use. **No new env override** (Q2): derive from `homeDir`;
|
|
647
|
+
revisit only if an `AGENTS_DIR` convention is later confirmed. Skill nests as `<shared>/talking-stick/SKILL.md`,
|
|
648
|
+
matching the proprietary layout.
|
|
649
|
+
|
|
650
|
+
### 12.4 Codex's three convergence questions — answered
|
|
651
|
+
|
|
652
|
+
1. **`tt install --all` with Codex/Grok/OpenCode detected but `agy` absent → still write shared?**
|
|
653
|
+
**YES.** `~/.agents/skills/talking-stick` is the *primary* target for those harnesses, independent of
|
|
654
|
+
Antigravity. `--all` writes the shared skill once whenever ≥1 shared-reading harness is detected.
|
|
655
|
+
Antigravity detection (`which agy`) only adds nothing extra (same shared target, deduped).
|
|
656
|
+
|
|
657
|
+
2. **Does `tt uninstall codex` remove the shared skill when Grok/OpenCode also use it?**
|
|
658
|
+
**NO — shared removal is explicit, never a side effect of a single harness uninstall.** Concrete rule:
|
|
659
|
+
- `tt uninstall <single shared+proprietary harness>` (codex|grok|opencode) removes **only** that
|
|
660
|
+
harness's own targets: its proprietary duplicate(s) and its extras (e.g. Grok hook). It **leaves the
|
|
661
|
+
shared skill in place** and prints: *"Left ~/.agents/skills/talking-stick (shared with other agents).
|
|
662
|
+
Run `tt uninstall --all` or `tt uninstall antigravity` to remove the shared skill."*
|
|
663
|
+
- The shared `~/.agents/skills/talking-stick` is removed **iff** the uninstall target set is `--all`,
|
|
664
|
+
**or** includes `antigravity` (shared-only → its uninstall *is* the shared removal), **or** an explicit
|
|
665
|
+
future `agents` pseudo-target. Rejected: reference-counting by "detected" harnesses (fragile, depends
|
|
666
|
+
on transient PATH/config state). Deterministic-by-target-set is the rule.
|
|
667
|
+
- Uninstall **never** removes the `~/.agents/skills` parent, only the `talking-stick` subdir (§4.7).
|
|
668
|
+
|
|
669
|
+
3. **Is symlink-only duplicate pruning enough for v1?**
|
|
670
|
+
**YES.** Confirmed by §12.1: every existing install is a symlink, so symlink-only auto-prune covers the
|
|
671
|
+
entire real migration set. Copied/unknown `talking-stick` dirs are **preserved and reported**, not
|
|
672
|
+
deleted; a `--prune-duplicates` opt-in for copies is deferred (only build it if a real copy appears).
|
|
673
|
+
|
|
674
|
+
### 12.5 Implementation build sequence (for the post-compaction execution turn)
|
|
675
|
+
|
|
676
|
+
Ordered so each step is independently testable and the cleanup never runs before the shared install exists:
|
|
677
|
+
|
|
678
|
+
1. **Model map + resolver.** Add `SkillLoadingModel` + the per-harness map (§12.3) and
|
|
679
|
+
`resolveSharedAgentsSkillsDir`. Add the **drift-guard test** asserting `SUPPORTED_HARNESSES`,
|
|
680
|
+
`FILE_SKILL_HARNESSES`, `HARNESS_COMMAND_MAPPING`, `HarnessCliHarness`, instruction aliases agree with it.
|
|
681
|
+
2. **Antigravity identity.** `detectHarnessSignal` env branch (CONVERSATION_ID anchor → TRAJECTORY_ID →
|
|
682
|
+
ancestry), `HARNESS_COMMAND_MAPPING` (`agy`,`antigravity` → antigravity), `HarnessCliHarness` union,
|
|
683
|
+
`detectHarness` (`which agy`). Tests per §6.1 + §11.4.6.
|
|
684
|
+
3. **Install planning rewrite.** `planInstallActionsForHarness` derives target(s) from the model; dedup
|
|
685
|
+
actions by absolute real path **before** the `Promise.all` run (kills the remove→symlink race, §4.3/§11.2.5).
|
|
686
|
+
Shared-reading harnesses → shared primary install + enqueue proprietary-dup cleanup actions (ordered
|
|
687
|
+
*after* the shared install/verify).
|
|
688
|
+
4. **Duplicate cleanup (symlink-only).** New action that removes a proprietary `talking-stick` **iff** it is
|
|
689
|
+
a symlink resolving to the bundled source; else preserve + report. Journal via the generalized audit (D3).
|
|
690
|
+
Wire into install, uninstall, self-update, first-run-after-version-change (reuse `update-migration.ts`).
|
|
691
|
+
5. **`syncInstalledSkills` update.** Sync the **shared** target for shared-reading harnesses and **stop
|
|
692
|
+
recreating** their proprietary copies (else silent sync re-introduces the duplicate). Most important
|
|
693
|
+
silent-path edit (§4.5). Test §11.4.4.
|
|
694
|
+
6. **Gemini deprecation.** `tt install gemini` → deprecation notice + cleanup-only; drop from `--all`
|
|
695
|
+
install set; best-effort `gemini skills uninstall` + `gemini mcp remove` guarded by `which gemini`.
|
|
696
|
+
Keep detection + token + `## Gemini` parse alias. Tests §6.5 / §11.4.5.
|
|
697
|
+
7. **Uninstall target-awareness.** Implement the §13.2 Option B rule (operator-confirmed): single-harness
|
|
698
|
+
uninstall — **including `antigravity`** — leaves the shared skill and prints the explicit-removal hint;
|
|
699
|
+
shared `~/.agents/skills/talking-stick` is removed **iff** target set is `--all` **or** the explicit
|
|
700
|
+
pseudo-target `tt uninstall agents` (== `--shared`); never remove the parent dir. Test §6.6.
|
|
701
|
+
8. **Instructions + docs.** `## Antigravity` in default template (replacing `## Gemini`), `InstructionHarness`
|
|
702
|
+
+ aliases, help text `claude|codex|antigravity|grok|opencode` (gemini deprecated), README §"How
|
|
703
|
+
installation works per harness", SKILL.md harness list + silent-sync note, CLAUDE.md dogfooding notes,
|
|
704
|
+
CHANGELOG + `docs/releases/<next>.md`.
|
|
705
|
+
9. **Full suite + typecheck + build + dist smoke + real `tt install --all` dogfood**, then release.
|
|
706
|
+
|
|
707
|
+
Risk register (§9) and the strict tt-managed safety gate (§4.5/§11.2.3-4) remain in force. No remaining
|
|
708
|
+
blocking open questions — Q1, Q3, Q4, Q6, Q8 resolved above; Q5/Q7 resolved as symlink-only + later-major.
|
|
709
|
+
|
|
710
|
+
## 13. Second-pass convergence review (Claude `claude:b6de450a`, 2026-06-13)
|
|
711
|
+
|
|
712
|
+
Independent review of Codex's §11 and the first convergence pass (§12). §12 is accepted as
|
|
713
|
+
authoritative; this pass confirms one of Codex's three convergence questions, refines a second, and
|
|
714
|
+
pins down the third. Net: the design stands; **one CLI-contract refinement (§13.2) needs operator
|
|
715
|
+
confirmation** before §12.5 step 7. No code changes this turn.
|
|
716
|
+
|
|
717
|
+
### 13.1 Symlink-only duplicate pruning (Codex Q3 / §12.4.3) — AGREE
|
|
718
|
+
|
|
719
|
+
Confirmed. §12.1's live check (every current install is a symlink resolving to the bundled source)
|
|
720
|
+
means symlink-only auto-prune covers the entire real migration set; copies/unknown dirs are
|
|
721
|
+
preserved-and-reported, and a `--prune-duplicates` opt-in for copies is correctly deferred until a
|
|
722
|
+
real copy appears. No digest table for v1. Nothing to add.
|
|
723
|
+
|
|
724
|
+
### 13.2 Shared uninstall semantics (Codex Q2 / §12.4.2) — AGREE on the principle, DISAGREE on one clause
|
|
725
|
+
|
|
726
|
+
> **RESOLVED 2026-06-13 (operator): Option B.** `tt uninstall antigravity` (like every single-harness
|
|
727
|
+
> uninstall) **leaves** the shared `~/.agents/skills/talking-stick` and prints the explicit-removal hint.
|
|
728
|
+
> The shared skill is removed **only** by `tt uninstall --all` or the new explicit pseudo-target
|
|
729
|
+
> `tt uninstall agents` (== `--shared`). The "or includes antigravity" clause from §12.4.2 is **dropped**.
|
|
730
|
+
> This is the authoritative contract for §12.5 step 7; the discussion below is the rationale.
|
|
731
|
+
|
|
732
|
+
The principle in §12.4.2 is right: shared removal must be **explicit** and never a side effect of a
|
|
733
|
+
single-harness uninstall, and reference-counting by "detected" harnesses is correctly rejected as
|
|
734
|
+
fragile. **But the clause "shared is removed iff the target set ... includes `antigravity`"
|
|
735
|
+
reintroduces exactly the side effect the rule forbids.**
|
|
736
|
+
|
|
737
|
+
Why it breaks: after migration (§12.3) Codex, Grok, and OpenCode have their proprietary copies pruned
|
|
738
|
+
and read `talking-stick` **only** from `~/.agents/skills/talking-stick`. Antigravity is `shared` —
|
|
739
|
+
the same single location. So `tt uninstall antigravity` removing the shared skill silently strips
|
|
740
|
+
`talking-stick` from Codex, Grok, and OpenCode as well: a destructive cross-harness side effect, no
|
|
741
|
+
different in kind from `tt uninstall codex` nuking the shared dir, which §12.4.2 rightly forbids.
|
|
742
|
+
|
|
743
|
+
**Proposed resolution (stays within "deterministic by target set, no reference counting"):**
|
|
744
|
+
|
|
745
|
+
- Shared `~/.agents/skills/talking-stick` is removed **iff** the target set is `--all` **or** an
|
|
746
|
+
explicit shared pseudo-target (`tt uninstall agents`, equivalently `--shared`). Promote that
|
|
747
|
+
pseudo-target from "future" (§12.4.2) to the **v1** mechanism.
|
|
748
|
+
- **Drop the `or includes antigravity` clause.** `tt uninstall antigravity` behaves like the other
|
|
749
|
+
single-harness uninstalls: it removes only Antigravity's own extras (none today) and **leaves** the
|
|
750
|
+
shared skill in place, printing the same message — *"Left ~/.agents/skills/talking-stick (shared
|
|
751
|
+
with other agents). Run `tt uninstall --all` or `tt uninstall agents` to remove the shared skill."*
|
|
752
|
+
- Rationale: Antigravity reads only the shared dir, so "uninstall `talking-stick` for just
|
|
753
|
+
Antigravity" is not physically separable from the other shared-readers. The honest behavior is to
|
|
754
|
+
refuse the silent shared deletion and name the explicit command. Least-surprise and least-harm both
|
|
755
|
+
favor this.
|
|
756
|
+
- **Operator confirmation requested:** this changes a user-facing *destructive* command contract
|
|
757
|
+
(whether `tt uninstall antigravity` ever removes the shared skill). Resolve at/before §12.5 step 7.
|
|
758
|
+
- If the operator prefers §12's original clause instead, it must be guarded: `tt uninstall antigravity`
|
|
759
|
+
would have to refuse/warn while any other shared-reading harness is still installed — which is the
|
|
760
|
+
reference-counting we are avoiding. Option B above is the cleaner contract.
|
|
761
|
+
|
|
762
|
+
### 13.3 Exact live `agy` discovery before cleanup (Codex §11.1 / §11.2.8) — CALL OUT + pin procedure
|
|
763
|
+
|
|
764
|
+
§12 keeps the live `agy` check as an implementation-time item but never specifies the *method*,
|
|
765
|
+
because (Q4, re-confirmed) `agy` has **no** `skills`/`mcp` introspection subcommand. Unlike
|
|
766
|
+
`codex debug prompt-input`, `grok inspect --json`, and `opencode debug skill`, there is no documented
|
|
767
|
+
`agy` command that prints its skill-loader paths — so "discover what `agy` reads" is not yet a known
|
|
768
|
+
command. Pin the procedure as:
|
|
769
|
+
|
|
770
|
+
1. **Re-confirm no CLI surface:** `agy --help`, `agy plugin --help`, `agy changelog` (Q4 re-check at
|
|
771
|
+
implementation time).
|
|
772
|
+
2. **Empirical loader probe:** create a unique sentinel skill at
|
|
773
|
+
`~/.agents/skills/tt-probe-<rand>/SKILL.md`, start an `agy` session, confirm `agy` surfaces/loads
|
|
774
|
+
the sentinel, then delete it. This is the concrete evidence that `agy` reads `~/.agents/skills` —
|
|
775
|
+
required **before** treating an install there as effective for Antigravity.
|
|
776
|
+
3. **Gemini-era compat:** only if `~/.gemini/antigravity/skills` (or any `~/.gemini/antigravity` skill
|
|
777
|
+
path) exists at implementation time, repeat the probe there before deleting any `talking-stick`
|
|
778
|
+
entry — migrate-then-remove if read, treat as stale if not. Not present on this machine today
|
|
779
|
+
(§12.1), so there is **no** Antigravity cleanup to gate in v1.
|
|
780
|
+
4. **Record** observed loader paths in the implementation handoff (per §11.2.8).
|
|
781
|
+
|
|
782
|
+
Scope note: because Antigravity's duplicate-cleanup target set is empty (§12.3), the `agy`-discovery
|
|
783
|
+
gate is really a **pre-install** verification ("does `agy` read `~/.agents/skills`?") plus a defensive
|
|
784
|
+
guard on the hypothetical `~/.gemini/antigravity` copy — not a gate on any deletion that exists today.
|
|
785
|
+
|
|
786
|
+
### 13.4 Status after this pass
|
|
787
|
+
|
|
788
|
+
Design converged. §12 stands; §13.2 is the single refinement requiring operator confirmation
|
|
789
|
+
(the `tt uninstall antigravity` → shared-removal contract), to be settled at/before §12.5 step 7.
|
|
790
|
+
§13.3 pins the `agy`-discovery procedure for the implementation turn. Everything else in §12 —
|
|
791
|
+
the map-driven model (D1), Antigravity identity (D2), audit generalization (D3), Gemini
|
|
792
|
+
deprecate-keep-detection (D4/D5), shared-default (D6), the per-harness table (§12.3), and the
|
|
793
|
+
build sequence (§12.5) — is accepted as-is.
|