Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .agents/skills/architecture/references/code-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@

| Domain | Files | Top entries |
|--------|-------|-------------|
| src | 44 | `src/commands/doc-init.js`, `src/lib/runner.js`, `src/lib/target.js` |
| src | 45 | `src/commands/doc-init.js`, `src/lib/runner.js`, `src/lib/target.js` |

**High-churn hotspots:**
- `src/commands/doc-init.js` - 34 changes
- `src/commands/doc-sync.js` - 20 changes
- `src/commands/doc-init.js` - 35 changes
- `src/commands/doc-sync.js` - 21 changes
- `src/lib/runner.js` - 17 changes

6 changes: 4 additions & 2 deletions .agents/skills/codex-support/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ You are working on **multi-target output support** — the system that lets aspe
- **Target definitions:** `TARGETS.claude` (centralized) and `TARGETS.codex` (directory-scoped). Each defines paths and capability flags: `supportsHooks`, `supportsSettings`, `supportsGraph`, `supportsSkills`, `needsActivationSection`, `needsCodeMapEmbed`, `supportsMCP`. Codex also has `maxInstructionsBytes` (32 KiB) and `userSkillsDir`.
- **Canonical generation:** Generation always produces Claude-canonical format first. Prompts always receive `CANONICAL_VARS` (hardcoded Claude paths from `doc-init.js`). Transforms run **after** generation to produce other target formats.
- **Content transform:** `transformForTarget()` remaps paths and content. For Codex: base skill → root `AGENTS.md`, domain skills → both `.agents/skills/{domain}/SKILL.md` and source directory `AGENTS.md`. `generateCodexSkillReferences()` creates `.agents/skills/architecture/` with code-map data.
- **Instructions file disk fallback:** `transformToDirectoryScoped` loads `instructionsFile` from disk via `repoPath` context parameter when it's not in the canonical files array (e.g., during `doc init --strategy skip-existing` or incremental `doc sync`). Uses `existsSync`/`readFileSync` from `fs`.
- **Content sanitization:** `sanitizeCodexInstructions()` and `sanitizeCodexSkill()` strip Claude-specific references (hooks, skill-rules.json, Claude Code mentions) from Codex output.
- **`ensureRootKeyFilesSection(content, graphSerialized)`** — Post-processes root instructions file to guarantee a `## Key Files` section with top hub files from the graph.
- **`mergeConfiguredTargets(existing, next)`** — Merges target arrays to avoid dropping previously configured targets during narrower runs. Validates against `TARGETS` keys, deduplicates.
Expand All @@ -37,7 +38,7 @@ You are working on **multi-target output support** — the system that lets aspe
- **Config persistence:** `.aspens.json` at repo root stores `{ targets, backend, version, saveTokens? }`. `readConfig()` returns `null` if missing **or if the config is structurally invalid**. `isValidConfig()` validates targets, backend, version, and `saveTokens` (via `isValidSaveTokensConfig()`).
- **Feature config (`saveTokens`):** Optional object in `.aspens.json` validated by `isValidSaveTokensConfig()` — checks `enabled` (boolean), `warnAtTokens`/`compactAtTokens` (positive integers, compact > warn unless either is `MAX_SAFE_INTEGER`), `saveHandoff`/`sessionRotation` (booleans), optional `claude`/`codex` sub-objects with `enabled` and `mode`.
- **`writeConfig` preserves feature config:** `writeConfig()` reads existing config and merges — `saveTokens` preserved unless explicitly set to `null` (intentional removal) or `undefined` (keep existing). Targets and backend also merge with existing.
- **Multi-target publish:** `doc-sync` uses `publishFilesForTargets()` to generate output for all configured targets from a single LLM run.
- **Multi-target publish:** `doc-sync` uses `publishFilesForTargets()` to generate output for all configured targets from a single LLM run. `repoPath` is passed through to the transform context.
- **Codex inference tightened:** `inferConfig()` only adds `'codex'` to inferred targets when `.codex/` config dir or `.agents/skills/` dir exists.
- **Conditional architecture ref:** Codex `buildCodexSkillRefs()` only includes the architecture skill reference when a graph was actually serialized.

Expand All @@ -48,9 +49,10 @@ You are working on **multi-target output support** — the system that lets aspe
- **Codex-only restrictions:** `add agent/command/hook` and `customize agents` throw `CliError` for Codex-only repos. `add skill` works for both targets.
- **Graph/hooks are Claude-only** — `persistGraphArtifacts()` returns data without writing files when `target.supportsGraph === false`. Hook installation skipped when `supportsHooks === false`.
- **Config validation is defensive** — `readConfig()` treats malformed but parseable JSON (e.g., wrong types for `targets`/`backend`/`version`/`saveTokens`) as invalid and returns `null`, same as missing config.
- **`repoPath` context is required for disk fallback** — callers of `transformForTarget` must pass `repoPath` in the context object for `instructionsFile` to load from disk when not in canonical files.

## References
- **Patterns:** See `src/lib/target.js` for all target property definitions

---
**Last Updated:** 2026-04-09
**Last Updated:** 2026-04-25
8 changes: 4 additions & 4 deletions .agents/skills/doc-sync/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ You are working on **doc-sync**, the incremental skill update command (`aspens d

## Key Concepts
- **Monorepo-aware:** `getGitRoot(repoPath)` resolves the actual git root. `projectPrefix` (`toGitRelative`) computes the subdirectory offset. `scopeProjectFiles()` filters changed files to the project subdirectory. Diffs are fetched from `gitRoot` but file paths are project-relative.
- **Multi-target publish:** `configuredTargets()` reads `.aspens.json` for all configured targets. `chooseSyncSourceTarget()` picks the best source (prefers Claude if both exist). LLM generates for the source target; `publishFilesForTargets()` transforms output for all other configured targets. `graphSerialized` is passed through to control conditional architecture references.
- **Multi-target publish:** `configuredTargets()` reads `.aspens.json` for all configured targets. `chooseSyncSourceTarget()` picks the best source (prefers Claude if both exist). LLM generates for the source target; `publishFilesForTargets()` transforms output for all other configured targets. `graphSerialized` and `repoPath` are passed through to the transform context for conditional architecture references and disk-based instructions file loading.
- **Backend routing:** `runLLM()` from `runner.js` dispatches to `runClaude()` or `runCodex()` based on `config.backend` (defaults to source target's id).
- **Diff-based flow:** Gets `git diff HEAD~N..HEAD` from git root, scopes changed files to project prefix, then feeds diff plus existing skill contents and graph context to the selected backend.
- **Prompt path variables:** Passes `{ skillsDir, skillFilename, instructionsFile, configDir }` from source target to `loadPrompt()` for path substitution in prompts.
- **Refresh mode (`--refresh`):** Skips diff entirely. Reviews every skill against the current codebase. Base skill refreshed first, then domain skills in parallel batches of `PARALLEL_LIMIT` (3). Also refreshes instructions file and reports uncovered domains.
- **Graph rebuild on every sync:** Calls `buildRepoGraph` + `persistGraphArtifacts` (with source target) to keep graph fresh. `graphSerialized` return value is captured and forwarded to `publishFilesForTargets` for conditional Codex architecture refs. Graph failure is non-fatal.
- **Unparseable response detection:** After LLM returns, if output has content but no `<file>` tags at all, throws `CliError` instead of silently treating it as "no updates needed".
- **Graceful response handling:** After LLM returns, if output has content but no `<file>` tags, treats it as "no updates needed" with a verbose-only warning. The prompt explicitly requests an empty response when nothing needs updating.
- **Graph-aware skill mapping:** `mapChangesToSkills()` checks direct file matches via `fileMatchesActivation()` (from `skill-reader.js`) and also whether changed files are imported by files matching a skill's activation block.
- **Interactive file picker:** When diff exceeds 80k chars and TTY is available, offers multiselect with skill-relevant files pre-selected.
- **Prioritized diff:** `buildPrioritizedDiff()` gives skill-relevant files 60k char budget, everything else 20k (80k total). Cuts at `diff --git` boundaries.
Expand All @@ -53,7 +53,7 @@ You are working on **doc-sync**, the incremental skill update command (`aspens d
## Critical Rules
- `runLLM` is called with `allowedTools: ['Read', 'Glob', 'Grep']` — doc-sync must never grant write tools.
- `parseOutput` restricts paths based on `getAllowedPaths([sourceTarget])` — paths outside the allowed set are silently dropped.
- **Unparseable output is an error** — if LLM returns text without any `<file>` tags, doc-sync throws `CliError` rather than silently proceeding with zero files.
- **Unparseable output is a soft warning** — if LLM returns text without any `<file>` tags, doc-sync logs a verbose warning and treats it as "no updates needed" instead of throwing.
- `getGitDiff` gracefully falls back from N commits to 1 if fewer available. `actualCommits` tracks what was used.
- The command exits early with `CliError` if the source target's skills directory doesn't exist.
- `checkMissingHooks()` in `bin/cli.js` only checks for Claude skills (not Codex — Codex doesn't use hooks).
Expand All @@ -64,4 +64,4 @@ You are working on **doc-sync**, the incremental skill update command (`aspens d
- **Patterns:** `src/lib/skill-reader.js` — `GENERIC_PATH_SEGMENTS`, `fileMatchesActivation()`, `getActivationBlock()`

---
**Last Updated:** 2026-04-08
**Last Updated:** 2026-04-25
6 changes: 4 additions & 2 deletions .claude/skills/codex-support/skill.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ You are working on **multi-target output support** — the system that lets aspe
- **Target definitions:** `TARGETS.claude` (centralized) and `TARGETS.codex` (directory-scoped). Each defines paths and capability flags: `supportsHooks`, `supportsSettings`, `supportsGraph`, `supportsSkills`, `needsActivationSection`, `needsCodeMapEmbed`, `supportsMCP`. Codex also has `maxInstructionsBytes` (32 KiB) and `userSkillsDir`.
- **Canonical generation:** Generation always produces Claude-canonical format first. Prompts always receive `CANONICAL_VARS` (hardcoded Claude paths from `doc-init.js`). Transforms run **after** generation to produce other target formats.
- **Content transform:** `transformForTarget()` remaps paths and content. For Codex: base skill → root `AGENTS.md`, domain skills → both `.agents/skills/{domain}/SKILL.md` and source directory `AGENTS.md`. `generateCodexSkillReferences()` creates `.agents/skills/architecture/` with code-map data.
- **Instructions file disk fallback:** `transformToDirectoryScoped` loads `instructionsFile` from disk via `repoPath` context parameter when it's not in the canonical files array (e.g., during `doc init --strategy skip-existing` or incremental `doc sync`). Uses `existsSync`/`readFileSync` from `fs`.
- **Content sanitization:** `sanitizeCodexInstructions()` and `sanitizeCodexSkill()` strip Claude-specific references (hooks, skill-rules.json, Claude Code mentions) from Codex output.
- **`ensureRootKeyFilesSection(content, graphSerialized)`** — Post-processes root instructions file to guarantee a `## Key Files` section with top hub files from the graph.
- **`mergeConfiguredTargets(existing, next)`** — Merges target arrays to avoid dropping previously configured targets during narrower runs. Validates against `TARGETS` keys, deduplicates.
Expand All @@ -37,7 +38,7 @@ You are working on **multi-target output support** — the system that lets aspe
- **Config persistence:** `.aspens.json` at repo root stores `{ targets, backend, version, saveTokens? }`. `readConfig()` returns `null` if missing **or if the config is structurally invalid**. `isValidConfig()` validates targets, backend, version, and `saveTokens` (via `isValidSaveTokensConfig()`).
- **Feature config (`saveTokens`):** Optional object in `.aspens.json` validated by `isValidSaveTokensConfig()` — checks `enabled` (boolean), `warnAtTokens`/`compactAtTokens` (positive integers, compact > warn unless either is `MAX_SAFE_INTEGER`), `saveHandoff`/`sessionRotation` (booleans), optional `claude`/`codex` sub-objects with `enabled` and `mode`.
- **`writeConfig` preserves feature config:** `writeConfig()` reads existing config and merges — `saveTokens` preserved unless explicitly set to `null` (intentional removal) or `undefined` (keep existing). Targets and backend also merge with existing.
- **Multi-target publish:** `doc-sync` uses `publishFilesForTargets()` to generate output for all configured targets from a single LLM run.
- **Multi-target publish:** `doc-sync` uses `publishFilesForTargets()` to generate output for all configured targets from a single LLM run. `repoPath` is passed through to the transform context.
- **Codex inference tightened:** `inferConfig()` only adds `'codex'` to inferred targets when `.codex/` config dir or `.agents/skills/` dir exists.
- **Conditional architecture ref:** Codex `buildCodexSkillRefs()` only includes the architecture skill reference when a graph was actually serialized.

Expand All @@ -48,9 +49,10 @@ You are working on **multi-target output support** — the system that lets aspe
- **Codex-only restrictions:** `add agent/command/hook` and `customize agents` throw `CliError` for Codex-only repos. `add skill` works for both targets.
- **Graph/hooks are Claude-only** — `persistGraphArtifacts()` returns data without writing files when `target.supportsGraph === false`. Hook installation skipped when `supportsHooks === false`.
- **Config validation is defensive** — `readConfig()` treats malformed but parseable JSON (e.g., wrong types for `targets`/`backend`/`version`/`saveTokens`) as invalid and returns `null`, same as missing config.
- **`repoPath` context is required for disk fallback** — callers of `transformForTarget` must pass `repoPath` in the context object for `instructionsFile` to load from disk when not in canonical files.

## References
- **Patterns:** See `src/lib/target.js` for all target property definitions

---
**Last Updated:** 2026-04-09
**Last Updated:** 2026-04-25
8 changes: 4 additions & 4 deletions .claude/skills/doc-sync/skill.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ You are working on **doc-sync**, the incremental skill update command (`aspens d

## Key Concepts
- **Monorepo-aware:** `getGitRoot(repoPath)` resolves the actual git root. `projectPrefix` (`toGitRelative`) computes the subdirectory offset. `scopeProjectFiles()` filters changed files to the project subdirectory. Diffs are fetched from `gitRoot` but file paths are project-relative.
- **Multi-target publish:** `configuredTargets()` reads `.aspens.json` for all configured targets. `chooseSyncSourceTarget()` picks the best source (prefers Claude if both exist). LLM generates for the source target; `publishFilesForTargets()` transforms output for all other configured targets. `graphSerialized` is passed through to control conditional architecture references.
- **Multi-target publish:** `configuredTargets()` reads `.aspens.json` for all configured targets. `chooseSyncSourceTarget()` picks the best source (prefers Claude if both exist). LLM generates for the source target; `publishFilesForTargets()` transforms output for all other configured targets. `graphSerialized` and `repoPath` are passed through to the transform context for conditional architecture references and disk-based instructions file loading.
- **Backend routing:** `runLLM()` from `runner.js` dispatches to `runClaude()` or `runCodex()` based on `config.backend` (defaults to source target's id).
- **Diff-based flow:** Gets `git diff HEAD~N..HEAD` from git root, scopes changed files to project prefix, then feeds diff plus existing skill contents and graph context to the selected backend.
- **Prompt path variables:** Passes `{ skillsDir, skillFilename, instructionsFile, configDir }` from source target to `loadPrompt()` for path substitution in prompts.
- **Refresh mode (`--refresh`):** Skips diff entirely. Reviews every skill against the current codebase. Base skill refreshed first, then domain skills in parallel batches of `PARALLEL_LIMIT` (3). Also refreshes instructions file and reports uncovered domains.
- **Graph rebuild on every sync:** Calls `buildRepoGraph` + `persistGraphArtifacts` (with source target) to keep graph fresh. `graphSerialized` return value is captured and forwarded to `publishFilesForTargets` for conditional Codex architecture refs. Graph failure is non-fatal.
- **Unparseable response detection:** After LLM returns, if output has content but no `<file>` tags at all, throws `CliError` instead of silently treating it as "no updates needed".
- **Graceful response handling:** After LLM returns, if output has content but no `<file>` tags, treats it as "no updates needed" with a verbose-only warning. The prompt explicitly requests an empty response when nothing needs updating.
- **Graph-aware skill mapping:** `mapChangesToSkills()` checks direct file matches via `fileMatchesActivation()` (from `skill-reader.js`) and also whether changed files are imported by files matching a skill's activation block.
- **Interactive file picker:** When diff exceeds 80k chars and TTY is available, offers multiselect with skill-relevant files pre-selected.
- **Prioritized diff:** `buildPrioritizedDiff()` gives skill-relevant files 60k char budget, everything else 20k (80k total). Cuts at `diff --git` boundaries.
Expand All @@ -53,7 +53,7 @@ You are working on **doc-sync**, the incremental skill update command (`aspens d
## Critical Rules
- `runLLM` is called with `allowedTools: ['Read', 'Glob', 'Grep']` — doc-sync must never grant write tools.
- `parseOutput` restricts paths based on `getAllowedPaths([sourceTarget])` — paths outside the allowed set are silently dropped.
- **Unparseable output is an error** — if LLM returns text without any `<file>` tags, doc-sync throws `CliError` rather than silently proceeding with zero files.
- **Unparseable output is a soft warning** — if LLM returns text without any `<file>` tags, doc-sync logs a verbose warning and treats it as "no updates needed" instead of throwing.
- `getGitDiff` gracefully falls back from N commits to 1 if fewer available. `actualCommits` tracks what was used.
- The command exits early with `CliError` if the source target's skills directory doesn't exist.
- `checkMissingHooks()` in `bin/cli.js` only checks for Claude skills (not Codex — Codex doesn't use hooks).
Expand All @@ -64,4 +64,4 @@ You are working on **doc-sync**, the incremental skill update command (`aspens d
- **Patterns:** `src/lib/skill-reader.js` — `GENERIC_PATH_SEGMENTS`, `fileMatchesActivation()`, `getActivationBlock()`

---
**Last Updated:** 2026-04-08
**Last Updated:** 2026-04-25
Loading
Loading