Deliver the Codex asset-producer subagent reliably (#161)

Codex reads custom subagents from .codex/agents/*.toml, a directory
separate from where it reads skills (.agents/skills). Skill installers
(notably `npx skills add`, see vercel-labs/skills#1290) only carry the
skills/ subtree, so the asset-producer agent was never delivered.

- build: bundle the codex .toml inside the skill dir for the variants
  Codex loads as a skill (agents, codex), so it travels with the skill.
- cli: skills install/update now write .codex/agents/ for Codex-likely
  projects (a .agents target or a global ~/.codex); update heals a
  missing sidecar. Non-Codex projects are untouched.
- context.mjs: on boot under a Codex install, emit a self-healing
  CODEX_AGENT_MISSING directive pointing at the bundled copy when the
  project's .codex/agents/ definition is absent. Self-resolves on copy.

CLI 2.2.0 -> 2.3.0 (published). Skill stays 3.5.0 (unpublished); the
note is folded into the existing 3.5.0 changelog entry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-05-28 15:07:40 -07:00
co-authored by Claude Opus 4.8
parent e58a4c571f
commit 7253b3870a
19 changed files with 1056 additions and 28 deletions
@@ -0,0 +1,92 @@
name = "impeccable_asset_producer"
description = "Produces clean reusable raster assets from approved Impeccable mock references without redesigning the direction."
model_reasoning_effort = "medium"
nickname_candidates = ["Asset Plate", "Clean Plate", "Crop Cutter"]
developer_instructions = '''
# Impeccable Asset Producer
You are the asset production agent for Impeccable craft.
Your job is production cleanup, not new art direction. Work only from the approved mock, assigned crops, contact sheets, and constraints the parent agent gives you. The assets you create will be used to build a real site, so treat every raster as a raw ingredient that HTML, CSS, SVG, canvas, and component code will compose.
## Core Rule
Do not redesign. Preserve the reference's visual role, silhouette, palette, lighting, material, texture, camera angle, and composition unless the parent explicitly asks for a change. Preserve perspective only when it belongs to the object or scene itself; if CSS should create the card transform, shadow, rounded clipping, border, or layout, remove that presentation chrome from the raster.
## Input Contract
Expect:
- Approved mock path or screenshot reference.
- Crop paths or a contact sheet with crop ids.
- Output directory.
- Required dimensions, format, transparency needs, and avoid list.
- Notes on what should remain semantic HTML/CSS/SVG instead of raster.
If the source mock is attached but has no filesystem path, use it for visual planning. Ask for a path only before cropping or writing assets.
Use defaults unless contradicted:
- `.webp` for opaque photos, backgrounds, and textures.
- `.png` for transparent cutouts, seals, tickets, and illustrations.
- Target production size or at least 2x display size when dimensions are known. Do not use small full-page mock crop size as the default shipping size.
- Remove UI text, navigation, buttons, labels, and body copy by default.
- Keep physical marks only when the parent says they are part of the asset.
- Remove letterboxing, empty padding, baked card corners, borders, shadows, caption bands, and layout background unless the parent says those pixels are intrinsic to the asset.
- Keep the final assets directory clean: only files the build will consume belong there. Put source crops, reference crops, masks, and contact sheets in a sibling `_sources`, `sources`, or review folder.
Ask blockers once, globally. Missing source path/crops or output directory blocks production. Exact dimensions, compression targets, retina variants, and format preferences do not block; choose defaults and report them.
## Workflow
1. Inventory the full approved mock or every assigned crop.
2. Put each visual role in exactly one bucket:
- `produce`: needs generation, image editing, cleanup, cutout work, or a clean plate before it can ship.
- `direct`: can ship as a crop, format conversion, compression pass, or sourced replacement with no generative cleanup.
- `semantic`: build in HTML/CSS/SVG/canvas, no raster output.
3. Treat full-page mock crops as references, not production-resolution source assets. Put a role in `direct` only when the provided source is already a clean, sufficiently large source asset with no semantic text or presentation chrome.
4. Give the parent an execution order for the `produce` bucket.
5. For produced assets, choose the least inventive strategy: image-to-image clean plate, faithful regeneration from crop reference, transparent cutout, texture/pattern reconstruction, stock/project source, or semantic HTML/CSS/SVG recommendation if raster is wrong.
6. Treat every crop as binding reference. In Codex, use the imagegen skill and built-in `image_gen` path by default when generation or editing is needed.
7. Remove baked-in UI text, navigation, buttons, body copy, and mock chrome unless the text is part of the asset.
8. Think through the final DOM/CSS representation before generating. If CSS will own radius, clipping, shadows, borders, perspective, responsive cropping, captions, or card frames, do not bake those into the bitmap.
9. Save outputs non-destructively in the requested project directory.
10. Compare each output against its source crop. If a review/QA tool is available, run it before the final manifest, then retry each major/fatal finding once before finalizing.
Use `direct` only for provided source assets that can already ship after crop tightening, conversion, compression, or naming. Do not ship a small crop from the full-page mock as `direct` just because it looks close.
Use `texture/pattern extraction` only when the source region is already clean enough to sample as texture. If UI, cards, labels, headings, body copy, or footer chrome must be removed to make a reusable texture or background, classify it as crop-derived cleanup or clean-plate work.
Use `semantic` for dashboards, charts, controls, screenshots of whole UI sections, data widgets, card chrome, app frames, icon toolbars, logos, wordmarks, and anything the final implementation can render crisply in HTML/CSS/SVG/canvas. Only ship a screenshot raster when the parent explicitly says the screenshot itself is the final asset.
Semantic does not mean ignored. For every semantic role, write a concrete implementation handoff for the parent craft agent: name the DOM/component layers, CSS-owned visual treatment, SVG/canvas/icon-library pieces, responsive behavior, and which nearby produced raster assets it should compose with. For logos and icons, prefer inline SVG/vector or icon-library implementation unless the parent provides a production logo raster.
For transparency, prefer true alpha output when the tool supports it. If it does not, request a flat chroma-key background in a color that cannot appear in the subject, then post-process that color to alpha before shipping a PNG/WebP. Do not ship the keyed background as the final asset.
## Prompt Pattern
Use this shape for image-to-image work:
```text
Use the provided crop as the approved visual reference.
Recreate the same asset as a clean reusable production image at the target component aspect ratio and at least 2x display resolution.
Preserve silhouette, object/scene perspective, camera angle, palette, lighting, material, texture, and visual role.
Remove baked-in UI copy, navigation, buttons, labels, body text, watermarks, and mock chrome unless explicitly part of the asset.
Remove letterboxing, padding, card borders, rounded clipping, CSS shadows, perspective transforms, caption bands, and layout backgrounds that the implementation should create in code.
Do not add new objects. Do not change the concept. Do not redesign the composition.
```
For transparent cutouts, use the imagegen skill's built-in-first chroma-key workflow unless the parent explicitly authorizes a true native transparency fallback.
## Output Contract
Return a complete manifest, grouped by `produce`, `direct`, and `semantic`. For each asset include: `id`, `source_crop`, `output_path` when applicable, `strategy`, `prompt_used` when applicable, `dimensions`, `format`, `transparency`, `deviations`, and `qa_status`.
For each semantic row include `id`, `implementation`, `notes`, and `qa_status`. The `implementation` must be a concrete build handoff, not a short explanation that no asset was produced. It should name the likely HTML/CSS/SVG/canvas/icon/component pieces and the visual responsibilities that code owns.
`qa_status` must be `accepted`, `needs_parent_review`, or `blocked`. Use `accepted` only after visual comparison passes. Use `needs_parent_review` for cut-off subjects, unwanted borders or rounded-card chrome, letterboxing, baked semantic text, low-resolution output, perspective that should have been CSS, missing transparency, or drift from the crop. Use `blocked` when inputs, permissions, image capability, or asset source quality prevent a credible result.
End with `execution_order`, `blockers`, and `assumptions` sections. Keep blockers global and minimal. Do not repeat missing inputs in every row; per-asset rows should carry only asset-specific risks or decisions.
Do not modify implementation code. Do not edit the approved mock. Do not produce final page copy. The parent craft agent owns implementation and final mock fidelity.
'''
+64 -2
View File
@@ -218,9 +218,56 @@ async function computeUpdateDirective(now = Date.now()) {
}
}
// ─── Codex subagent self-heal ───────────────────────────────────────────────
// Codex reads custom subagents from .codex/agents/*.toml, a sibling of the
// skill dir that skill installers (notably `npx skills add`) don't carry. The
// build bundles the .toml inside the Codex skill variants, so when this module
// runs under a Codex install and the project is missing the subagent, point the
// agent at the bundled copy. Self-resolves the moment the file is copied.
const CODEX_AGENT_FILE = 'impeccable_asset_producer.toml';
/**
* Returns a one-time directive when (a) the running harness is Codex -- detected
* purely from this module's install path, since each harness loads its own skill
* copy -- and (b) the bundled subagent .toml exists but the project's
* .codex/agents/ copy does not. Returns null in every other case. Best-effort:
* any error yields null and never disrupts context output.
*/
export function computeCodexAgentDirective({ modulePath, fileExists = fs.existsSync } = {}) {
try {
if (!modulePath) return null;
const here = path.dirname(modulePath);
const skillRoot = path.resolve(here, '..');
const providerDir = path.basename(path.resolve(here, '..', '..', '..'));
const projectRoot = path.resolve(here, '..', '..', '..', '..');
// Only the variants Codex loads as a skill carry the bundled subagent.
if (providerDir !== '.agents' && providerDir !== '.codex') return null;
const bundledToml = path.join(skillRoot, 'agents', CODEX_AGENT_FILE);
const installedToml = path.join(projectRoot, '.codex', 'agents', CODEX_AGENT_FILE);
if (!fileExists(bundledToml)) return null; // older build without the bundled copy
if (fileExists(installedToml)) return null; // already installed -- nothing to do
const destDir = path.join(projectRoot, '.codex', 'agents');
return (
`CODEX_AGENT_MISSING: The Impeccable asset-producer subagent is not installed for Codex. ` +
`Codex reads custom subagents from .codex/agents/*.toml, but ${installedToml} is missing. ` +
`To enable it, copy the bundled definition once: ` +
`\`mkdir -p "${destDir}" && cp "${bundledToml}" "${destDir}/"\`. ` +
`This is optional and only affects the asset-production subagent; continue the current task either ` +
`way, and do not raise this again this session.`
);
} catch {
return null;
}
}
async function cli() {
const ctx = loadContext(process.cwd());
const updateDirective = await computeUpdateDirective();
const codexDirective = computeCodexAgentDirective({ modulePath: fileURLToPath(import.meta.url) });
if (!ctx.hasProduct) {
// Direct stdout message instead of relying on empty output as a signal
@@ -231,6 +278,7 @@ async function cli() {
'instructions to write PRODUCT.md before resuming.',
];
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
process.exit(0);
}
@@ -244,10 +292,24 @@ async function cli() {
: `NEXT STEP: You MUST now read the matching register reference (\`reference/brand.md\` or \`reference/product.md\`) before producing any design output. Pick based on PRODUCT.md above.`;
parts.push(next);
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
}
const _running = process.argv[1];
if (_running?.endsWith('context.mjs') || _running?.endsWith('context.mjs/')) {
// Run cli() only when this module is the entry point. Compare realpaths
// rather than endsWith(): a loose suffix match also fires for unrelated
// scripts like `load-context.mjs`, and realpath tolerates symlinked
// invocation (the test harness symlinks the skill dir).
function invokedAsScript() {
const arg = process.argv[1];
if (!arg) return false;
try {
return fs.realpathSync(arg) === fs.realpathSync(fileURLToPath(import.meta.url));
} catch {
return false;
}
}
if (invokedAsScript()) {
cli();
}
+64 -2
View File
@@ -218,9 +218,56 @@ async function computeUpdateDirective(now = Date.now()) {
}
}
// ─── Codex subagent self-heal ───────────────────────────────────────────────
// Codex reads custom subagents from .codex/agents/*.toml, a sibling of the
// skill dir that skill installers (notably `npx skills add`) don't carry. The
// build bundles the .toml inside the Codex skill variants, so when this module
// runs under a Codex install and the project is missing the subagent, point the
// agent at the bundled copy. Self-resolves the moment the file is copied.
const CODEX_AGENT_FILE = 'impeccable_asset_producer.toml';
/**
* Returns a one-time directive when (a) the running harness is Codex -- detected
* purely from this module's install path, since each harness loads its own skill
* copy -- and (b) the bundled subagent .toml exists but the project's
* .codex/agents/ copy does not. Returns null in every other case. Best-effort:
* any error yields null and never disrupts context output.
*/
export function computeCodexAgentDirective({ modulePath, fileExists = fs.existsSync } = {}) {
try {
if (!modulePath) return null;
const here = path.dirname(modulePath);
const skillRoot = path.resolve(here, '..');
const providerDir = path.basename(path.resolve(here, '..', '..', '..'));
const projectRoot = path.resolve(here, '..', '..', '..', '..');
// Only the variants Codex loads as a skill carry the bundled subagent.
if (providerDir !== '.agents' && providerDir !== '.codex') return null;
const bundledToml = path.join(skillRoot, 'agents', CODEX_AGENT_FILE);
const installedToml = path.join(projectRoot, '.codex', 'agents', CODEX_AGENT_FILE);
if (!fileExists(bundledToml)) return null; // older build without the bundled copy
if (fileExists(installedToml)) return null; // already installed -- nothing to do
const destDir = path.join(projectRoot, '.codex', 'agents');
return (
`CODEX_AGENT_MISSING: The Impeccable asset-producer subagent is not installed for Codex. ` +
`Codex reads custom subagents from .codex/agents/*.toml, but ${installedToml} is missing. ` +
`To enable it, copy the bundled definition once: ` +
`\`mkdir -p "${destDir}" && cp "${bundledToml}" "${destDir}/"\`. ` +
`This is optional and only affects the asset-production subagent; continue the current task either ` +
`way, and do not raise this again this session.`
);
} catch {
return null;
}
}
async function cli() {
const ctx = loadContext(process.cwd());
const updateDirective = await computeUpdateDirective();
const codexDirective = computeCodexAgentDirective({ modulePath: fileURLToPath(import.meta.url) });
if (!ctx.hasProduct) {
// Direct stdout message instead of relying on empty output as a signal
@@ -231,6 +278,7 @@ async function cli() {
'instructions to write PRODUCT.md before resuming.',
];
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
process.exit(0);
}
@@ -244,10 +292,24 @@ async function cli() {
: `NEXT STEP: You MUST now read the matching register reference (\`reference/brand.md\` or \`reference/product.md\`) before producing any design output. Pick based on PRODUCT.md above.`;
parts.push(next);
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
}
const _running = process.argv[1];
if (_running?.endsWith('context.mjs') || _running?.endsWith('context.mjs/')) {
// Run cli() only when this module is the entry point. Compare realpaths
// rather than endsWith(): a loose suffix match also fires for unrelated
// scripts like `load-context.mjs`, and realpath tolerates symlinked
// invocation (the test harness symlinks the skill dir).
function invokedAsScript() {
const arg = process.argv[1];
if (!arg) return false;
try {
return fs.realpathSync(arg) === fs.realpathSync(fileURLToPath(import.meta.url));
} catch {
return false;
}
}
if (invokedAsScript()) {
cli();
}
+64 -2
View File
@@ -218,9 +218,56 @@ async function computeUpdateDirective(now = Date.now()) {
}
}
// ─── Codex subagent self-heal ───────────────────────────────────────────────
// Codex reads custom subagents from .codex/agents/*.toml, a sibling of the
// skill dir that skill installers (notably `npx skills add`) don't carry. The
// build bundles the .toml inside the Codex skill variants, so when this module
// runs under a Codex install and the project is missing the subagent, point the
// agent at the bundled copy. Self-resolves the moment the file is copied.
const CODEX_AGENT_FILE = 'impeccable_asset_producer.toml';
/**
* Returns a one-time directive when (a) the running harness is Codex -- detected
* purely from this module's install path, since each harness loads its own skill
* copy -- and (b) the bundled subagent .toml exists but the project's
* .codex/agents/ copy does not. Returns null in every other case. Best-effort:
* any error yields null and never disrupts context output.
*/
export function computeCodexAgentDirective({ modulePath, fileExists = fs.existsSync } = {}) {
try {
if (!modulePath) return null;
const here = path.dirname(modulePath);
const skillRoot = path.resolve(here, '..');
const providerDir = path.basename(path.resolve(here, '..', '..', '..'));
const projectRoot = path.resolve(here, '..', '..', '..', '..');
// Only the variants Codex loads as a skill carry the bundled subagent.
if (providerDir !== '.agents' && providerDir !== '.codex') return null;
const bundledToml = path.join(skillRoot, 'agents', CODEX_AGENT_FILE);
const installedToml = path.join(projectRoot, '.codex', 'agents', CODEX_AGENT_FILE);
if (!fileExists(bundledToml)) return null; // older build without the bundled copy
if (fileExists(installedToml)) return null; // already installed -- nothing to do
const destDir = path.join(projectRoot, '.codex', 'agents');
return (
`CODEX_AGENT_MISSING: The Impeccable asset-producer subagent is not installed for Codex. ` +
`Codex reads custom subagents from .codex/agents/*.toml, but ${installedToml} is missing. ` +
`To enable it, copy the bundled definition once: ` +
`\`mkdir -p "${destDir}" && cp "${bundledToml}" "${destDir}/"\`. ` +
`This is optional and only affects the asset-production subagent; continue the current task either ` +
`way, and do not raise this again this session.`
);
} catch {
return null;
}
}
async function cli() {
const ctx = loadContext(process.cwd());
const updateDirective = await computeUpdateDirective();
const codexDirective = computeCodexAgentDirective({ modulePath: fileURLToPath(import.meta.url) });
if (!ctx.hasProduct) {
// Direct stdout message instead of relying on empty output as a signal
@@ -231,6 +278,7 @@ async function cli() {
'instructions to write PRODUCT.md before resuming.',
];
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
process.exit(0);
}
@@ -244,10 +292,24 @@ async function cli() {
: `NEXT STEP: You MUST now read the matching register reference (\`reference/brand.md\` or \`reference/product.md\`) before producing any design output. Pick based on PRODUCT.md above.`;
parts.push(next);
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
}
const _running = process.argv[1];
if (_running?.endsWith('context.mjs') || _running?.endsWith('context.mjs/')) {
// Run cli() only when this module is the entry point. Compare realpaths
// rather than endsWith(): a loose suffix match also fires for unrelated
// scripts like `load-context.mjs`, and realpath tolerates symlinked
// invocation (the test harness symlinks the skill dir).
function invokedAsScript() {
const arg = process.argv[1];
if (!arg) return false;
try {
return fs.realpathSync(arg) === fs.realpathSync(fileURLToPath(import.meta.url));
} catch {
return false;
}
}
if (invokedAsScript()) {
cli();
}
+64 -2
View File
@@ -218,9 +218,56 @@ async function computeUpdateDirective(now = Date.now()) {
}
}
// ─── Codex subagent self-heal ───────────────────────────────────────────────
// Codex reads custom subagents from .codex/agents/*.toml, a sibling of the
// skill dir that skill installers (notably `npx skills add`) don't carry. The
// build bundles the .toml inside the Codex skill variants, so when this module
// runs under a Codex install and the project is missing the subagent, point the
// agent at the bundled copy. Self-resolves the moment the file is copied.
const CODEX_AGENT_FILE = 'impeccable_asset_producer.toml';
/**
* Returns a one-time directive when (a) the running harness is Codex -- detected
* purely from this module's install path, since each harness loads its own skill
* copy -- and (b) the bundled subagent .toml exists but the project's
* .codex/agents/ copy does not. Returns null in every other case. Best-effort:
* any error yields null and never disrupts context output.
*/
export function computeCodexAgentDirective({ modulePath, fileExists = fs.existsSync } = {}) {
try {
if (!modulePath) return null;
const here = path.dirname(modulePath);
const skillRoot = path.resolve(here, '..');
const providerDir = path.basename(path.resolve(here, '..', '..', '..'));
const projectRoot = path.resolve(here, '..', '..', '..', '..');
// Only the variants Codex loads as a skill carry the bundled subagent.
if (providerDir !== '.agents' && providerDir !== '.codex') return null;
const bundledToml = path.join(skillRoot, 'agents', CODEX_AGENT_FILE);
const installedToml = path.join(projectRoot, '.codex', 'agents', CODEX_AGENT_FILE);
if (!fileExists(bundledToml)) return null; // older build without the bundled copy
if (fileExists(installedToml)) return null; // already installed -- nothing to do
const destDir = path.join(projectRoot, '.codex', 'agents');
return (
`CODEX_AGENT_MISSING: The Impeccable asset-producer subagent is not installed for Codex. ` +
`Codex reads custom subagents from .codex/agents/*.toml, but ${installedToml} is missing. ` +
`To enable it, copy the bundled definition once: ` +
`\`mkdir -p "${destDir}" && cp "${bundledToml}" "${destDir}/"\`. ` +
`This is optional and only affects the asset-production subagent; continue the current task either ` +
`way, and do not raise this again this session.`
);
} catch {
return null;
}
}
async function cli() {
const ctx = loadContext(process.cwd());
const updateDirective = await computeUpdateDirective();
const codexDirective = computeCodexAgentDirective({ modulePath: fileURLToPath(import.meta.url) });
if (!ctx.hasProduct) {
// Direct stdout message instead of relying on empty output as a signal
@@ -231,6 +278,7 @@ async function cli() {
'instructions to write PRODUCT.md before resuming.',
];
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
process.exit(0);
}
@@ -244,10 +292,24 @@ async function cli() {
: `NEXT STEP: You MUST now read the matching register reference (\`reference/brand.md\` or \`reference/product.md\`) before producing any design output. Pick based on PRODUCT.md above.`;
parts.push(next);
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
}
const _running = process.argv[1];
if (_running?.endsWith('context.mjs') || _running?.endsWith('context.mjs/')) {
// Run cli() only when this module is the entry point. Compare realpaths
// rather than endsWith(): a loose suffix match also fires for unrelated
// scripts like `load-context.mjs`, and realpath tolerates symlinked
// invocation (the test harness symlinks the skill dir).
function invokedAsScript() {
const arg = process.argv[1];
if (!arg) return false;
try {
return fs.realpathSync(arg) === fs.realpathSync(fileURLToPath(import.meta.url));
} catch {
return false;
}
}
if (invokedAsScript()) {
cli();
}
+64 -2
View File
@@ -218,9 +218,56 @@ async function computeUpdateDirective(now = Date.now()) {
}
}
// ─── Codex subagent self-heal ───────────────────────────────────────────────
// Codex reads custom subagents from .codex/agents/*.toml, a sibling of the
// skill dir that skill installers (notably `npx skills add`) don't carry. The
// build bundles the .toml inside the Codex skill variants, so when this module
// runs under a Codex install and the project is missing the subagent, point the
// agent at the bundled copy. Self-resolves the moment the file is copied.
const CODEX_AGENT_FILE = 'impeccable_asset_producer.toml';
/**
* Returns a one-time directive when (a) the running harness is Codex -- detected
* purely from this module's install path, since each harness loads its own skill
* copy -- and (b) the bundled subagent .toml exists but the project's
* .codex/agents/ copy does not. Returns null in every other case. Best-effort:
* any error yields null and never disrupts context output.
*/
export function computeCodexAgentDirective({ modulePath, fileExists = fs.existsSync } = {}) {
try {
if (!modulePath) return null;
const here = path.dirname(modulePath);
const skillRoot = path.resolve(here, '..');
const providerDir = path.basename(path.resolve(here, '..', '..', '..'));
const projectRoot = path.resolve(here, '..', '..', '..', '..');
// Only the variants Codex loads as a skill carry the bundled subagent.
if (providerDir !== '.agents' && providerDir !== '.codex') return null;
const bundledToml = path.join(skillRoot, 'agents', CODEX_AGENT_FILE);
const installedToml = path.join(projectRoot, '.codex', 'agents', CODEX_AGENT_FILE);
if (!fileExists(bundledToml)) return null; // older build without the bundled copy
if (fileExists(installedToml)) return null; // already installed -- nothing to do
const destDir = path.join(projectRoot, '.codex', 'agents');
return (
`CODEX_AGENT_MISSING: The Impeccable asset-producer subagent is not installed for Codex. ` +
`Codex reads custom subagents from .codex/agents/*.toml, but ${installedToml} is missing. ` +
`To enable it, copy the bundled definition once: ` +
`\`mkdir -p "${destDir}" && cp "${bundledToml}" "${destDir}/"\`. ` +
`This is optional and only affects the asset-production subagent; continue the current task either ` +
`way, and do not raise this again this session.`
);
} catch {
return null;
}
}
async function cli() {
const ctx = loadContext(process.cwd());
const updateDirective = await computeUpdateDirective();
const codexDirective = computeCodexAgentDirective({ modulePath: fileURLToPath(import.meta.url) });
if (!ctx.hasProduct) {
// Direct stdout message instead of relying on empty output as a signal
@@ -231,6 +278,7 @@ async function cli() {
'instructions to write PRODUCT.md before resuming.',
];
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
process.exit(0);
}
@@ -244,10 +292,24 @@ async function cli() {
: `NEXT STEP: You MUST now read the matching register reference (\`reference/brand.md\` or \`reference/product.md\`) before producing any design output. Pick based on PRODUCT.md above.`;
parts.push(next);
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
}
const _running = process.argv[1];
if (_running?.endsWith('context.mjs') || _running?.endsWith('context.mjs/')) {
// Run cli() only when this module is the entry point. Compare realpaths
// rather than endsWith(): a loose suffix match also fires for unrelated
// scripts like `load-context.mjs`, and realpath tolerates symlinked
// invocation (the test harness symlinks the skill dir).
function invokedAsScript() {
const arg = process.argv[1];
if (!arg) return false;
try {
return fs.realpathSync(arg) === fs.realpathSync(fileURLToPath(import.meta.url));
} catch {
return false;
}
}
if (invokedAsScript()) {
cli();
}
+64 -2
View File
@@ -218,9 +218,56 @@ async function computeUpdateDirective(now = Date.now()) {
}
}
// ─── Codex subagent self-heal ───────────────────────────────────────────────
// Codex reads custom subagents from .codex/agents/*.toml, a sibling of the
// skill dir that skill installers (notably `npx skills add`) don't carry. The
// build bundles the .toml inside the Codex skill variants, so when this module
// runs under a Codex install and the project is missing the subagent, point the
// agent at the bundled copy. Self-resolves the moment the file is copied.
const CODEX_AGENT_FILE = 'impeccable_asset_producer.toml';
/**
* Returns a one-time directive when (a) the running harness is Codex -- detected
* purely from this module's install path, since each harness loads its own skill
* copy -- and (b) the bundled subagent .toml exists but the project's
* .codex/agents/ copy does not. Returns null in every other case. Best-effort:
* any error yields null and never disrupts context output.
*/
export function computeCodexAgentDirective({ modulePath, fileExists = fs.existsSync } = {}) {
try {
if (!modulePath) return null;
const here = path.dirname(modulePath);
const skillRoot = path.resolve(here, '..');
const providerDir = path.basename(path.resolve(here, '..', '..', '..'));
const projectRoot = path.resolve(here, '..', '..', '..', '..');
// Only the variants Codex loads as a skill carry the bundled subagent.
if (providerDir !== '.agents' && providerDir !== '.codex') return null;
const bundledToml = path.join(skillRoot, 'agents', CODEX_AGENT_FILE);
const installedToml = path.join(projectRoot, '.codex', 'agents', CODEX_AGENT_FILE);
if (!fileExists(bundledToml)) return null; // older build without the bundled copy
if (fileExists(installedToml)) return null; // already installed -- nothing to do
const destDir = path.join(projectRoot, '.codex', 'agents');
return (
`CODEX_AGENT_MISSING: The Impeccable asset-producer subagent is not installed for Codex. ` +
`Codex reads custom subagents from .codex/agents/*.toml, but ${installedToml} is missing. ` +
`To enable it, copy the bundled definition once: ` +
`\`mkdir -p "${destDir}" && cp "${bundledToml}" "${destDir}/"\`. ` +
`This is optional and only affects the asset-production subagent; continue the current task either ` +
`way, and do not raise this again this session.`
);
} catch {
return null;
}
}
async function cli() {
const ctx = loadContext(process.cwd());
const updateDirective = await computeUpdateDirective();
const codexDirective = computeCodexAgentDirective({ modulePath: fileURLToPath(import.meta.url) });
if (!ctx.hasProduct) {
// Direct stdout message instead of relying on empty output as a signal
@@ -231,6 +278,7 @@ async function cli() {
'instructions to write PRODUCT.md before resuming.',
];
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
process.exit(0);
}
@@ -244,10 +292,24 @@ async function cli() {
: `NEXT STEP: You MUST now read the matching register reference (\`reference/brand.md\` or \`reference/product.md\`) before producing any design output. Pick based on PRODUCT.md above.`;
parts.push(next);
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
}
const _running = process.argv[1];
if (_running?.endsWith('context.mjs') || _running?.endsWith('context.mjs/')) {
// Run cli() only when this module is the entry point. Compare realpaths
// rather than endsWith(): a loose suffix match also fires for unrelated
// scripts like `load-context.mjs`, and realpath tolerates symlinked
// invocation (the test harness symlinks the skill dir).
function invokedAsScript() {
const arg = process.argv[1];
if (!arg) return false;
try {
return fs.realpathSync(arg) === fs.realpathSync(fileURLToPath(import.meta.url));
} catch {
return false;
}
}
if (invokedAsScript()) {
cli();
}
@@ -218,9 +218,56 @@ async function computeUpdateDirective(now = Date.now()) {
}
}
// ─── Codex subagent self-heal ───────────────────────────────────────────────
// Codex reads custom subagents from .codex/agents/*.toml, a sibling of the
// skill dir that skill installers (notably `npx skills add`) don't carry. The
// build bundles the .toml inside the Codex skill variants, so when this module
// runs under a Codex install and the project is missing the subagent, point the
// agent at the bundled copy. Self-resolves the moment the file is copied.
const CODEX_AGENT_FILE = 'impeccable_asset_producer.toml';
/**
* Returns a one-time directive when (a) the running harness is Codex -- detected
* purely from this module's install path, since each harness loads its own skill
* copy -- and (b) the bundled subagent .toml exists but the project's
* .codex/agents/ copy does not. Returns null in every other case. Best-effort:
* any error yields null and never disrupts context output.
*/
export function computeCodexAgentDirective({ modulePath, fileExists = fs.existsSync } = {}) {
try {
if (!modulePath) return null;
const here = path.dirname(modulePath);
const skillRoot = path.resolve(here, '..');
const providerDir = path.basename(path.resolve(here, '..', '..', '..'));
const projectRoot = path.resolve(here, '..', '..', '..', '..');
// Only the variants Codex loads as a skill carry the bundled subagent.
if (providerDir !== '.agents' && providerDir !== '.codex') return null;
const bundledToml = path.join(skillRoot, 'agents', CODEX_AGENT_FILE);
const installedToml = path.join(projectRoot, '.codex', 'agents', CODEX_AGENT_FILE);
if (!fileExists(bundledToml)) return null; // older build without the bundled copy
if (fileExists(installedToml)) return null; // already installed -- nothing to do
const destDir = path.join(projectRoot, '.codex', 'agents');
return (
`CODEX_AGENT_MISSING: The Impeccable asset-producer subagent is not installed for Codex. ` +
`Codex reads custom subagents from .codex/agents/*.toml, but ${installedToml} is missing. ` +
`To enable it, copy the bundled definition once: ` +
`\`mkdir -p "${destDir}" && cp "${bundledToml}" "${destDir}/"\`. ` +
`This is optional and only affects the asset-production subagent; continue the current task either ` +
`way, and do not raise this again this session.`
);
} catch {
return null;
}
}
async function cli() {
const ctx = loadContext(process.cwd());
const updateDirective = await computeUpdateDirective();
const codexDirective = computeCodexAgentDirective({ modulePath: fileURLToPath(import.meta.url) });
if (!ctx.hasProduct) {
// Direct stdout message instead of relying on empty output as a signal
@@ -231,6 +278,7 @@ async function cli() {
'instructions to write PRODUCT.md before resuming.',
];
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
process.exit(0);
}
@@ -244,10 +292,24 @@ async function cli() {
: `NEXT STEP: You MUST now read the matching register reference (\`reference/brand.md\` or \`reference/product.md\`) before producing any design output. Pick based on PRODUCT.md above.`;
parts.push(next);
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
}
const _running = process.argv[1];
if (_running?.endsWith('context.mjs') || _running?.endsWith('context.mjs/')) {
// Run cli() only when this module is the entry point. Compare realpaths
// rather than endsWith(): a loose suffix match also fires for unrelated
// scripts like `load-context.mjs`, and realpath tolerates symlinked
// invocation (the test harness symlinks the skill dir).
function invokedAsScript() {
const arg = process.argv[1];
if (!arg) return false;
try {
return fs.realpathSync(arg) === fs.realpathSync(fileURLToPath(import.meta.url));
} catch {
return false;
}
}
if (invokedAsScript()) {
cli();
}
+64 -2
View File
@@ -218,9 +218,56 @@ async function computeUpdateDirective(now = Date.now()) {
}
}
// ─── Codex subagent self-heal ───────────────────────────────────────────────
// Codex reads custom subagents from .codex/agents/*.toml, a sibling of the
// skill dir that skill installers (notably `npx skills add`) don't carry. The
// build bundles the .toml inside the Codex skill variants, so when this module
// runs under a Codex install and the project is missing the subagent, point the
// agent at the bundled copy. Self-resolves the moment the file is copied.
const CODEX_AGENT_FILE = 'impeccable_asset_producer.toml';
/**
* Returns a one-time directive when (a) the running harness is Codex -- detected
* purely from this module's install path, since each harness loads its own skill
* copy -- and (b) the bundled subagent .toml exists but the project's
* .codex/agents/ copy does not. Returns null in every other case. Best-effort:
* any error yields null and never disrupts context output.
*/
export function computeCodexAgentDirective({ modulePath, fileExists = fs.existsSync } = {}) {
try {
if (!modulePath) return null;
const here = path.dirname(modulePath);
const skillRoot = path.resolve(here, '..');
const providerDir = path.basename(path.resolve(here, '..', '..', '..'));
const projectRoot = path.resolve(here, '..', '..', '..', '..');
// Only the variants Codex loads as a skill carry the bundled subagent.
if (providerDir !== '.agents' && providerDir !== '.codex') return null;
const bundledToml = path.join(skillRoot, 'agents', CODEX_AGENT_FILE);
const installedToml = path.join(projectRoot, '.codex', 'agents', CODEX_AGENT_FILE);
if (!fileExists(bundledToml)) return null; // older build without the bundled copy
if (fileExists(installedToml)) return null; // already installed -- nothing to do
const destDir = path.join(projectRoot, '.codex', 'agents');
return (
`CODEX_AGENT_MISSING: The Impeccable asset-producer subagent is not installed for Codex. ` +
`Codex reads custom subagents from .codex/agents/*.toml, but ${installedToml} is missing. ` +
`To enable it, copy the bundled definition once: ` +
`\`mkdir -p "${destDir}" && cp "${bundledToml}" "${destDir}/"\`. ` +
`This is optional and only affects the asset-production subagent; continue the current task either ` +
`way, and do not raise this again this session.`
);
} catch {
return null;
}
}
async function cli() {
const ctx = loadContext(process.cwd());
const updateDirective = await computeUpdateDirective();
const codexDirective = computeCodexAgentDirective({ modulePath: fileURLToPath(import.meta.url) });
if (!ctx.hasProduct) {
// Direct stdout message instead of relying on empty output as a signal
@@ -231,6 +278,7 @@ async function cli() {
'instructions to write PRODUCT.md before resuming.',
];
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
process.exit(0);
}
@@ -244,10 +292,24 @@ async function cli() {
: `NEXT STEP: You MUST now read the matching register reference (\`reference/brand.md\` or \`reference/product.md\`) before producing any design output. Pick based on PRODUCT.md above.`;
parts.push(next);
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
}
const _running = process.argv[1];
if (_running?.endsWith('context.mjs') || _running?.endsWith('context.mjs/')) {
// Run cli() only when this module is the entry point. Compare realpaths
// rather than endsWith(): a loose suffix match also fires for unrelated
// scripts like `load-context.mjs`, and realpath tolerates symlinked
// invocation (the test harness symlinks the skill dir).
function invokedAsScript() {
const arg = process.argv[1];
if (!arg) return false;
try {
return fs.realpathSync(arg) === fs.realpathSync(fileURLToPath(import.meta.url));
} catch {
return false;
}
}
if (invokedAsScript()) {
cli();
}
+64 -2
View File
@@ -218,9 +218,56 @@ async function computeUpdateDirective(now = Date.now()) {
}
}
// ─── Codex subagent self-heal ───────────────────────────────────────────────
// Codex reads custom subagents from .codex/agents/*.toml, a sibling of the
// skill dir that skill installers (notably `npx skills add`) don't carry. The
// build bundles the .toml inside the Codex skill variants, so when this module
// runs under a Codex install and the project is missing the subagent, point the
// agent at the bundled copy. Self-resolves the moment the file is copied.
const CODEX_AGENT_FILE = 'impeccable_asset_producer.toml';
/**
* Returns a one-time directive when (a) the running harness is Codex -- detected
* purely from this module's install path, since each harness loads its own skill
* copy -- and (b) the bundled subagent .toml exists but the project's
* .codex/agents/ copy does not. Returns null in every other case. Best-effort:
* any error yields null and never disrupts context output.
*/
export function computeCodexAgentDirective({ modulePath, fileExists = fs.existsSync } = {}) {
try {
if (!modulePath) return null;
const here = path.dirname(modulePath);
const skillRoot = path.resolve(here, '..');
const providerDir = path.basename(path.resolve(here, '..', '..', '..'));
const projectRoot = path.resolve(here, '..', '..', '..', '..');
// Only the variants Codex loads as a skill carry the bundled subagent.
if (providerDir !== '.agents' && providerDir !== '.codex') return null;
const bundledToml = path.join(skillRoot, 'agents', CODEX_AGENT_FILE);
const installedToml = path.join(projectRoot, '.codex', 'agents', CODEX_AGENT_FILE);
if (!fileExists(bundledToml)) return null; // older build without the bundled copy
if (fileExists(installedToml)) return null; // already installed -- nothing to do
const destDir = path.join(projectRoot, '.codex', 'agents');
return (
`CODEX_AGENT_MISSING: The Impeccable asset-producer subagent is not installed for Codex. ` +
`Codex reads custom subagents from .codex/agents/*.toml, but ${installedToml} is missing. ` +
`To enable it, copy the bundled definition once: ` +
`\`mkdir -p "${destDir}" && cp "${bundledToml}" "${destDir}/"\`. ` +
`This is optional and only affects the asset-production subagent; continue the current task either ` +
`way, and do not raise this again this session.`
);
} catch {
return null;
}
}
async function cli() {
const ctx = loadContext(process.cwd());
const updateDirective = await computeUpdateDirective();
const codexDirective = computeCodexAgentDirective({ modulePath: fileURLToPath(import.meta.url) });
if (!ctx.hasProduct) {
// Direct stdout message instead of relying on empty output as a signal
@@ -231,6 +278,7 @@ async function cli() {
'instructions to write PRODUCT.md before resuming.',
];
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
process.exit(0);
}
@@ -244,10 +292,24 @@ async function cli() {
: `NEXT STEP: You MUST now read the matching register reference (\`reference/brand.md\` or \`reference/product.md\`) before producing any design output. Pick based on PRODUCT.md above.`;
parts.push(next);
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
}
const _running = process.argv[1];
if (_running?.endsWith('context.mjs') || _running?.endsWith('context.mjs/')) {
// Run cli() only when this module is the entry point. Compare realpaths
// rather than endsWith(): a loose suffix match also fires for unrelated
// scripts like `load-context.mjs`, and realpath tolerates symlinked
// invocation (the test harness symlinks the skill dir).
function invokedAsScript() {
const arg = process.argv[1];
if (!arg) return false;
try {
return fs.realpathSync(arg) === fs.realpathSync(fileURLToPath(import.meta.url));
} catch {
return false;
}
}
if (invokedAsScript()) {
cli();
}
+64 -2
View File
@@ -218,9 +218,56 @@ async function computeUpdateDirective(now = Date.now()) {
}
}
// ─── Codex subagent self-heal ───────────────────────────────────────────────
// Codex reads custom subagents from .codex/agents/*.toml, a sibling of the
// skill dir that skill installers (notably `npx skills add`) don't carry. The
// build bundles the .toml inside the Codex skill variants, so when this module
// runs under a Codex install and the project is missing the subagent, point the
// agent at the bundled copy. Self-resolves the moment the file is copied.
const CODEX_AGENT_FILE = 'impeccable_asset_producer.toml';
/**
* Returns a one-time directive when (a) the running harness is Codex -- detected
* purely from this module's install path, since each harness loads its own skill
* copy -- and (b) the bundled subagent .toml exists but the project's
* .codex/agents/ copy does not. Returns null in every other case. Best-effort:
* any error yields null and never disrupts context output.
*/
export function computeCodexAgentDirective({ modulePath, fileExists = fs.existsSync } = {}) {
try {
if (!modulePath) return null;
const here = path.dirname(modulePath);
const skillRoot = path.resolve(here, '..');
const providerDir = path.basename(path.resolve(here, '..', '..', '..'));
const projectRoot = path.resolve(here, '..', '..', '..', '..');
// Only the variants Codex loads as a skill carry the bundled subagent.
if (providerDir !== '.agents' && providerDir !== '.codex') return null;
const bundledToml = path.join(skillRoot, 'agents', CODEX_AGENT_FILE);
const installedToml = path.join(projectRoot, '.codex', 'agents', CODEX_AGENT_FILE);
if (!fileExists(bundledToml)) return null; // older build without the bundled copy
if (fileExists(installedToml)) return null; // already installed -- nothing to do
const destDir = path.join(projectRoot, '.codex', 'agents');
return (
`CODEX_AGENT_MISSING: The Impeccable asset-producer subagent is not installed for Codex. ` +
`Codex reads custom subagents from .codex/agents/*.toml, but ${installedToml} is missing. ` +
`To enable it, copy the bundled definition once: ` +
`\`mkdir -p "${destDir}" && cp "${bundledToml}" "${destDir}/"\`. ` +
`This is optional and only affects the asset-production subagent; continue the current task either ` +
`way, and do not raise this again this session.`
);
} catch {
return null;
}
}
async function cli() {
const ctx = loadContext(process.cwd());
const updateDirective = await computeUpdateDirective();
const codexDirective = computeCodexAgentDirective({ modulePath: fileURLToPath(import.meta.url) });
if (!ctx.hasProduct) {
// Direct stdout message instead of relying on empty output as a signal
@@ -231,6 +278,7 @@ async function cli() {
'instructions to write PRODUCT.md before resuming.',
];
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
process.exit(0);
}
@@ -244,10 +292,24 @@ async function cli() {
: `NEXT STEP: You MUST now read the matching register reference (\`reference/brand.md\` or \`reference/product.md\`) before producing any design output. Pick based on PRODUCT.md above.`;
parts.push(next);
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
}
const _running = process.argv[1];
if (_running?.endsWith('context.mjs') || _running?.endsWith('context.mjs/')) {
// Run cli() only when this module is the entry point. Compare realpaths
// rather than endsWith(): a loose suffix match also fires for unrelated
// scripts like `load-context.mjs`, and realpath tolerates symlinked
// invocation (the test harness symlinks the skill dir).
function invokedAsScript() {
const arg = process.argv[1];
if (!arg) return false;
try {
return fs.realpathSync(arg) === fs.realpathSync(fileURLToPath(import.meta.url));
} catch {
return false;
}
}
if (invokedAsScript()) {
cli();
}
+64 -2
View File
@@ -218,9 +218,56 @@ async function computeUpdateDirective(now = Date.now()) {
}
}
// ─── Codex subagent self-heal ───────────────────────────────────────────────
// Codex reads custom subagents from .codex/agents/*.toml, a sibling of the
// skill dir that skill installers (notably `npx skills add`) don't carry. The
// build bundles the .toml inside the Codex skill variants, so when this module
// runs under a Codex install and the project is missing the subagent, point the
// agent at the bundled copy. Self-resolves the moment the file is copied.
const CODEX_AGENT_FILE = 'impeccable_asset_producer.toml';
/**
* Returns a one-time directive when (a) the running harness is Codex -- detected
* purely from this module's install path, since each harness loads its own skill
* copy -- and (b) the bundled subagent .toml exists but the project's
* .codex/agents/ copy does not. Returns null in every other case. Best-effort:
* any error yields null and never disrupts context output.
*/
export function computeCodexAgentDirective({ modulePath, fileExists = fs.existsSync } = {}) {
try {
if (!modulePath) return null;
const here = path.dirname(modulePath);
const skillRoot = path.resolve(here, '..');
const providerDir = path.basename(path.resolve(here, '..', '..', '..'));
const projectRoot = path.resolve(here, '..', '..', '..', '..');
// Only the variants Codex loads as a skill carry the bundled subagent.
if (providerDir !== '.agents' && providerDir !== '.codex') return null;
const bundledToml = path.join(skillRoot, 'agents', CODEX_AGENT_FILE);
const installedToml = path.join(projectRoot, '.codex', 'agents', CODEX_AGENT_FILE);
if (!fileExists(bundledToml)) return null; // older build without the bundled copy
if (fileExists(installedToml)) return null; // already installed -- nothing to do
const destDir = path.join(projectRoot, '.codex', 'agents');
return (
`CODEX_AGENT_MISSING: The Impeccable asset-producer subagent is not installed for Codex. ` +
`Codex reads custom subagents from .codex/agents/*.toml, but ${installedToml} is missing. ` +
`To enable it, copy the bundled definition once: ` +
`\`mkdir -p "${destDir}" && cp "${bundledToml}" "${destDir}/"\`. ` +
`This is optional and only affects the asset-production subagent; continue the current task either ` +
`way, and do not raise this again this session.`
);
} catch {
return null;
}
}
async function cli() {
const ctx = loadContext(process.cwd());
const updateDirective = await computeUpdateDirective();
const codexDirective = computeCodexAgentDirective({ modulePath: fileURLToPath(import.meta.url) });
if (!ctx.hasProduct) {
// Direct stdout message instead of relying on empty output as a signal
@@ -231,6 +278,7 @@ async function cli() {
'instructions to write PRODUCT.md before resuming.',
];
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
process.exit(0);
}
@@ -244,10 +292,24 @@ async function cli() {
: `NEXT STEP: You MUST now read the matching register reference (\`reference/brand.md\` or \`reference/product.md\`) before producing any design output. Pick based on PRODUCT.md above.`;
parts.push(next);
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
}
const _running = process.argv[1];
if (_running?.endsWith('context.mjs') || _running?.endsWith('context.mjs/')) {
// Run cli() only when this module is the entry point. Compare realpaths
// rather than endsWith(): a loose suffix match also fires for unrelated
// scripts like `load-context.mjs`, and realpath tolerates symlinked
// invocation (the test harness symlinks the skill dir).
function invokedAsScript() {
const arg = process.argv[1];
if (!arg) return false;
try {
return fs.realpathSync(arg) === fs.realpathSync(fileURLToPath(import.meta.url));
} catch {
return false;
}
}
if (invokedAsScript()) {
cli();
}
+64 -2
View File
@@ -218,9 +218,56 @@ async function computeUpdateDirective(now = Date.now()) {
}
}
// ─── Codex subagent self-heal ───────────────────────────────────────────────
// Codex reads custom subagents from .codex/agents/*.toml, a sibling of the
// skill dir that skill installers (notably `npx skills add`) don't carry. The
// build bundles the .toml inside the Codex skill variants, so when this module
// runs under a Codex install and the project is missing the subagent, point the
// agent at the bundled copy. Self-resolves the moment the file is copied.
const CODEX_AGENT_FILE = 'impeccable_asset_producer.toml';
/**
* Returns a one-time directive when (a) the running harness is Codex -- detected
* purely from this module's install path, since each harness loads its own skill
* copy -- and (b) the bundled subagent .toml exists but the project's
* .codex/agents/ copy does not. Returns null in every other case. Best-effort:
* any error yields null and never disrupts context output.
*/
export function computeCodexAgentDirective({ modulePath, fileExists = fs.existsSync } = {}) {
try {
if (!modulePath) return null;
const here = path.dirname(modulePath);
const skillRoot = path.resolve(here, '..');
const providerDir = path.basename(path.resolve(here, '..', '..', '..'));
const projectRoot = path.resolve(here, '..', '..', '..', '..');
// Only the variants Codex loads as a skill carry the bundled subagent.
if (providerDir !== '.agents' && providerDir !== '.codex') return null;
const bundledToml = path.join(skillRoot, 'agents', CODEX_AGENT_FILE);
const installedToml = path.join(projectRoot, '.codex', 'agents', CODEX_AGENT_FILE);
if (!fileExists(bundledToml)) return null; // older build without the bundled copy
if (fileExists(installedToml)) return null; // already installed -- nothing to do
const destDir = path.join(projectRoot, '.codex', 'agents');
return (
`CODEX_AGENT_MISSING: The Impeccable asset-producer subagent is not installed for Codex. ` +
`Codex reads custom subagents from .codex/agents/*.toml, but ${installedToml} is missing. ` +
`To enable it, copy the bundled definition once: ` +
`\`mkdir -p "${destDir}" && cp "${bundledToml}" "${destDir}/"\`. ` +
`This is optional and only affects the asset-production subagent; continue the current task either ` +
`way, and do not raise this again this session.`
);
} catch {
return null;
}
}
async function cli() {
const ctx = loadContext(process.cwd());
const updateDirective = await computeUpdateDirective();
const codexDirective = computeCodexAgentDirective({ modulePath: fileURLToPath(import.meta.url) });
if (!ctx.hasProduct) {
// Direct stdout message instead of relying on empty output as a signal
@@ -231,6 +278,7 @@ async function cli() {
'instructions to write PRODUCT.md before resuming.',
];
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
process.exit(0);
}
@@ -244,10 +292,24 @@ async function cli() {
: `NEXT STEP: You MUST now read the matching register reference (\`reference/brand.md\` or \`reference/product.md\`) before producing any design output. Pick based on PRODUCT.md above.`;
parts.push(next);
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
}
const _running = process.argv[1];
if (_running?.endsWith('context.mjs') || _running?.endsWith('context.mjs/')) {
// Run cli() only when this module is the entry point. Compare realpaths
// rather than endsWith(): a loose suffix match also fires for unrelated
// scripts like `load-context.mjs`, and realpath tolerates symlinked
// invocation (the test harness symlinks the skill dir).
function invokedAsScript() {
const arg = process.argv[1];
if (!arg) return false;
try {
return fs.realpathSync(arg) === fs.realpathSync(fileURLToPath(import.meta.url));
} catch {
return false;
}
}
if (invokedAsScript()) {
cli();
}
+53 -1
View File
@@ -398,6 +398,36 @@ function copyProviderSkills(bundleDir, root, targets) {
return written;
}
/**
* Codex reads custom subagents from `.codex/agents/*.toml`, a sibling of the
* skill dir that the skills/ copy never touches. Treat it as a sidecar: only
* write it for projects that actually use Codex, so a pure Claude project
* doesn't get a stray `.codex/` folder. Codex-likely = the .agents (Codex
* skills) variant is a target, or a global ~/.codex install exists.
*/
function isCodexLikely(targets) {
return targets.includes('.agents') || existsSync(join(homedir(), '.codex'));
}
/**
* Copy the Codex subagent definitions from the bundle's top-level `.codex/agents`
* into the project's `.codex/agents`. Returns the number of files written (0 when
* the bundle has none).
*/
function installCodexAgents(bundleDir, root) {
const srcDir = join(bundleDir, '.codex', 'agents');
if (!existsSync(srcDir)) return 0;
const destDir = join(root, '.codex', 'agents');
let written = 0;
for (const entry of readdirSync(srcDir, { withFileTypes: true })) {
if (!entry.isFile()) continue;
mkdirSync(destDir, { recursive: true });
writeFileSync(join(destDir, entry.name), readFileSync(join(srcDir, entry.name)));
written++;
}
return written;
}
async function install(flags) {
const force = flags.includes('--force');
const yes = flags.includes('-y') || flags.includes('--yes');
@@ -443,8 +473,15 @@ async function install(flags) {
}
let written = 0;
let codexAgents = 0;
try {
written = copyProviderSkills(bundleDir, root, targets);
// Codex users also need the asset-producer subagent, which lives in
// .codex/agents/ (a sibling of the skill dir, not part of skills/). Do this
// before the bundle is cleaned up below. Best-effort: never fail the install.
if (isCodexLikely(targets)) {
try { codexAgents = installCodexAgents(bundleDir, root); } catch {}
}
} catch (e) {
rmSync(bundleDir, { recursive: true, force: true });
console.error(`Install failed: ${e.message}`);
@@ -457,6 +494,7 @@ async function install(flags) {
process.exit(1);
}
console.log(`Installed impeccable into: ${targets.join(', ')}`);
if (codexAgents > 0) console.log(`Installed ${codexAgents} Codex subagent(s) into .codex/agents/`);
// Ask about prefixing (skip in CI mode unless --prefix= is set)
let prefix = '';
@@ -665,9 +703,18 @@ async function update(flags = []) {
// Compare local vs remote -- skip if already up to date
if (isUpToDate(root, providers, tmpDir)) {
// Skills match, but the Codex subagent sidecar may still be missing (e.g.
// an `npx skills add` install that only carried skills/). Heal it before
// declaring nothing to do.
let healed = 0;
if (isCodexLikely(providers)
&& !existsSync(join(root, '.codex', 'agents', 'impeccable_asset_producer.toml'))) {
try { healed = installCodexAgents(tmpDir, root); } catch {}
}
rmSync(tmpDir, { recursive: true, force: true });
const v = getSkillsVersion(root);
console.log(`Skills are up to date${v ? ` (v${v})` : ''}. Nothing to do.`);
if (healed > 0) console.log(`Installed ${healed} Codex subagent(s) into .codex/agents/`);
console.log(`Skills are up to date${v ? ` (v${v})` : ''}.${healed > 0 ? '' : ' Nothing to do.'}`);
process.exit(0);
}
@@ -704,6 +751,11 @@ async function update(flags = []) {
}
}
// Refresh the Codex subagent sidecar (.codex/agents/) alongside the skills.
if (isCodexLikely(providers)) {
try { installCodexAgents(tmpDir, root); } catch {}
}
rmSync(tmpDir, { recursive: true, force: true });
// Re-apply prefix if detected
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "impeccable",
"version": "2.2.0",
"version": "2.3.0",
"author": "Paul Bakaus",
"description": "Design skills, commands, and anti-pattern detection for AI coding agents",
"keywords": [
+64 -2
View File
@@ -218,9 +218,56 @@ async function computeUpdateDirective(now = Date.now()) {
}
}
// ─── Codex subagent self-heal ───────────────────────────────────────────────
// Codex reads custom subagents from .codex/agents/*.toml, a sibling of the
// skill dir that skill installers (notably `npx skills add`) don't carry. The
// build bundles the .toml inside the Codex skill variants, so when this module
// runs under a Codex install and the project is missing the subagent, point the
// agent at the bundled copy. Self-resolves the moment the file is copied.
const CODEX_AGENT_FILE = 'impeccable_asset_producer.toml';
/**
* Returns a one-time directive when (a) the running harness is Codex -- detected
* purely from this module's install path, since each harness loads its own skill
* copy -- and (b) the bundled subagent .toml exists but the project's
* .codex/agents/ copy does not. Returns null in every other case. Best-effort:
* any error yields null and never disrupts context output.
*/
export function computeCodexAgentDirective({ modulePath, fileExists = fs.existsSync } = {}) {
try {
if (!modulePath) return null;
const here = path.dirname(modulePath);
const skillRoot = path.resolve(here, '..');
const providerDir = path.basename(path.resolve(here, '..', '..', '..'));
const projectRoot = path.resolve(here, '..', '..', '..', '..');
// Only the variants Codex loads as a skill carry the bundled subagent.
if (providerDir !== '.agents' && providerDir !== '.codex') return null;
const bundledToml = path.join(skillRoot, 'agents', CODEX_AGENT_FILE);
const installedToml = path.join(projectRoot, '.codex', 'agents', CODEX_AGENT_FILE);
if (!fileExists(bundledToml)) return null; // older build without the bundled copy
if (fileExists(installedToml)) return null; // already installed -- nothing to do
const destDir = path.join(projectRoot, '.codex', 'agents');
return (
`CODEX_AGENT_MISSING: The Impeccable asset-producer subagent is not installed for Codex. ` +
`Codex reads custom subagents from .codex/agents/*.toml, but ${installedToml} is missing. ` +
`To enable it, copy the bundled definition once: ` +
`\`mkdir -p "${destDir}" && cp "${bundledToml}" "${destDir}/"\`. ` +
`This is optional and only affects the asset-production subagent; continue the current task either ` +
`way, and do not raise this again this session.`
);
} catch {
return null;
}
}
async function cli() {
const ctx = loadContext(process.cwd());
const updateDirective = await computeUpdateDirective();
const codexDirective = computeCodexAgentDirective({ modulePath: fileURLToPath(import.meta.url) });
if (!ctx.hasProduct) {
// Direct stdout message instead of relying on empty output as a signal
@@ -231,6 +278,7 @@ async function cli() {
'instructions to write PRODUCT.md before resuming.',
];
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
process.exit(0);
}
@@ -244,10 +292,24 @@ async function cli() {
: `NEXT STEP: You MUST now read the matching register reference (\`reference/brand.md\` or \`reference/product.md\`) before producing any design output. Pick based on PRODUCT.md above.`;
parts.push(next);
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
}
const _running = process.argv[1];
if (_running?.endsWith('context.mjs') || _running?.endsWith('context.mjs/')) {
// Run cli() only when this module is the entry point. Compare realpaths
// rather than endsWith(): a loose suffix match also fires for unrelated
// scripts like `load-context.mjs`, and realpath tolerates symlinked
// invocation (the test harness symlinks the skill dir).
function invokedAsScript() {
const arg = process.argv[1];
if (!arg) return false;
try {
return fs.realpathSync(arg) === fs.realpathSync(fileURLToPath(import.meta.url));
} catch {
return false;
}
}
if (invokedAsScript()) {
cli();
}
+21
View File
@@ -49,6 +49,12 @@ const FIELD_SPECS = {
},
};
// Provider builds that Codex loads as a skill (it reads skills from .agents/skills,
// and the .codex build mirrors it). For these, the Codex subagent .toml also travels
// INSIDE the skill dir so context.mjs can point a running Codex agent at a local copy
// when the sibling .codex/agents/ definition is missing (see skill/scripts/context.mjs).
const CODEX_SKILL_PROVIDERS = new Set(['agents', 'codex']);
function humanizeSkillName(name) {
return name
.split('-')
@@ -259,6 +265,21 @@ export function createTransformer(config) {
scriptCount++;
}
}
// Bundle the Codex subagent .toml inside the skill dir for the variants
// Codex actually loads. The sibling .codex/agents/ definition is what Codex
// reads at runtime, but installers (notably `npx skills add`) only carry the
// skills/ subtree -- so context.mjs uses this in-skill copy to self-heal.
if (CODEX_SKILL_PROVIDERS.has(provider)) {
for (const agent of skill.agents || []) {
if (agent.providers && !agent.providers.includes('codex')) continue;
let agentBody = compileProviderBlocks(agent.body, providerTags);
agentBody = replacePlaceholders(agentBody, placeholderKey, [], allSkillNames);
const filename = `${agent.codexName || agent.name.replace(/-/g, '_')}.toml`;
ensureDir(path.join(skillDir, 'agents'));
writeFile(path.join(skillDir, 'agents', filename), buildCodexAgent(agent, agentBody));
}
}
}
if (config.agentFormat) {
+8
View File
@@ -58,10 +58,18 @@ import '../styles/changelog-faq-kinpaku.css';
<li><strong><code>/impeccable teach</code> is now <code>/impeccable init</code>.</strong> Renamed to match what it does: one command to set up a project. From a single codebase scan it writes PRODUCT.md, offers a DESIGN.md, configures Live Mode so it just works the first time you run it, then points you at the best command to start with. The old name still works as an alias.</li>
<li><strong>Detector: 7 new rules.</strong> <code>cream-palette</code>, <code>em-dash-overuse</code>, <code>marketing-buzzword</code>, <code>numbered-section-markers</code>, <code>aphoristic-cadence</code>, <code>broken-image</code>, and italic-serif display heroes. One canonical registry now feeds the CLI, the browser extension, critique, and the evals.</li>
<li><strong>The skill keeps itself current.</strong> On the first session of the day, Impeccable quietly checks whether a newer version shipped. If one has, it offers to run <code>npx impeccable skills update</code> for you. It always asks first, never nags about a version you declined, and never interrupts the task you're on. Set <code>IMPECCABLE_NO_UPDATE_CHECK=1</code> to turn it off.</li>
<li><strong>Codex gets its asset-producer subagent automatically.</strong> Codex reads custom subagents from <code>.codex/agents/</code>, a directory separate from where it reads skills, so installers used to leave the agent behind. Now the skill bundles the agent, notices on boot when a Codex project is missing it, and offers to copy it into place. Fixes the gap reported in #161.</li>
<li><strong>A tighter, sharper skill.</strong> Orphan reference files folded into their commands, context loading simplified, and a new LLM-backed test suite catches instruction-following regressions across three providers. Plus dedicated <a href="/changelog">/changelog</a> and <a href="/faq">/faq</a> pages.</li>
</ul>
</article>
<article id="cli-v2.3.0" class="cf-entry">
<header class="cf-entry-head"><span class="cf-version">CLI v2.3.0</span><span class="cf-date">May 28, 2026</span></header>
<ul class="cf-items">
<li><strong>Codex subagent delivery.</strong> <code>skills install</code> and <code>skills update</code> now write <code>.codex/agents/impeccable_asset_producer.toml</code> alongside the skill for Codex projects, detected from a <code>.agents</code> target or a global <code>~/.codex</code> install. Update heals the file when an older install left it out, and non-Codex projects stay untouched.</li>
</ul>
</article>
<article id="cli-v2.2.0" class="cf-entry">
<header class="cf-entry-head"><span class="cf-version">CLI v2.2.0</span><span class="cf-date">May 28, 2026</span></header>
<ul class="cf-items">
+49
View File
@@ -218,9 +218,56 @@ async function computeUpdateDirective(now = Date.now()) {
}
}
// ─── Codex subagent self-heal ───────────────────────────────────────────────
// Codex reads custom subagents from .codex/agents/*.toml, a sibling of the
// skill dir that skill installers (notably `npx skills add`) don't carry. The
// build bundles the .toml inside the Codex skill variants, so when this module
// runs under a Codex install and the project is missing the subagent, point the
// agent at the bundled copy. Self-resolves the moment the file is copied.
const CODEX_AGENT_FILE = 'impeccable_asset_producer.toml';
/**
* Returns a one-time directive when (a) the running harness is Codex -- detected
* purely from this module's install path, since each harness loads its own skill
* copy -- and (b) the bundled subagent .toml exists but the project's
* .codex/agents/ copy does not. Returns null in every other case. Best-effort:
* any error yields null and never disrupts context output.
*/
export function computeCodexAgentDirective({ modulePath, fileExists = fs.existsSync } = {}) {
try {
if (!modulePath) return null;
const here = path.dirname(modulePath);
const skillRoot = path.resolve(here, '..');
const providerDir = path.basename(path.resolve(here, '..', '..', '..'));
const projectRoot = path.resolve(here, '..', '..', '..', '..');
// Only the variants Codex loads as a skill carry the bundled subagent.
if (providerDir !== '.agents' && providerDir !== '.codex') return null;
const bundledToml = path.join(skillRoot, 'agents', CODEX_AGENT_FILE);
const installedToml = path.join(projectRoot, '.codex', 'agents', CODEX_AGENT_FILE);
if (!fileExists(bundledToml)) return null; // older build without the bundled copy
if (fileExists(installedToml)) return null; // already installed -- nothing to do
const destDir = path.join(projectRoot, '.codex', 'agents');
return (
`CODEX_AGENT_MISSING: The Impeccable asset-producer subagent is not installed for Codex. ` +
`Codex reads custom subagents from .codex/agents/*.toml, but ${installedToml} is missing. ` +
`To enable it, copy the bundled definition once: ` +
`\`mkdir -p "${destDir}" && cp "${bundledToml}" "${destDir}/"\`. ` +
`This is optional and only affects the asset-production subagent; continue the current task either ` +
`way, and do not raise this again this session.`
);
} catch {
return null;
}
}
async function cli() {
const ctx = loadContext(process.cwd());
const updateDirective = await computeUpdateDirective();
const codexDirective = computeCodexAgentDirective({ modulePath: fileURLToPath(import.meta.url) });
if (!ctx.hasProduct) {
// Direct stdout message instead of relying on empty output as a signal
@@ -231,6 +278,7 @@ async function cli() {
'instructions to write PRODUCT.md before resuming.',
];
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
process.exit(0);
}
@@ -244,6 +292,7 @@ async function cli() {
: `NEXT STEP: You MUST now read the matching register reference (\`reference/brand.md\` or \`reference/product.md\`) before producing any design output. Pick based on PRODUCT.md above.`;
parts.push(next);
if (updateDirective) parts.push(updateDirective);
if (codexDirective) parts.push(codexDirective);
process.stdout.write(parts.join('\n\n---\n\n') + '\n');
}