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
2 changes: 1 addition & 1 deletion .claude/skills/verify-open-pstack/features/grok.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Sub-features

`grok:dispatch`: a Grok parent running the installed `poteto-mode` routes an `inherit-parent` lane natively through `spawn_subagent` with `pstack:poteto-agent`, an explicit `grok:` lane through `pstack-runner --parent grok --provider grok`, and a Codex lane through `pstack-runner --parent grok`, and Grok offers only the model-free pstack agents. `grok:setup`: `/pstack:setup-pstack` on a Grok parent writes `${GROK_HOME:-$HOME/.grok}/rules/pstack-models.md`. Select them for a change to the Grok manifest or its `grok-agents/` copies, `provider-dispatch.md`, `codex-tools.md`, `model-catalog.md`, poteto-mode's `SKILL.md`, the runner's `types.ts`, `registry/index.ts` or `registry/render.ts`, `setup-pstack/SKILL.md`, `recipes.ts` or the Grok transport. A path that reaches them never adds them to every run; name them with `--feature grok:dispatch` or `--feature grok:setup`.
`grok:dispatch`: a Grok parent running the installed `poteto-mode` routes an `inherit-parent` lane natively through `spawn_subagent` with `pstack:poteto-agent`, an explicit `grok:` lane through `pstack-runner --parent grok --provider grok`, and a Codex lane through `pstack-runner --parent grok`, and Grok offers only the model-free pstack agents. `grok:setup`: `/pstack:setup-pstack` on a Grok parent writes `${GROK_HOME:-$HOME/.grok}/rules/pstack-models.md`. Any path that the registry owns as runtime code or instructions permits naming them. Assets keep their manifest consumer, and a version-only manifest change keeps its `hook:startup` reach. A path that reaches them never adds them to every run; name them with `--feature grok:dispatch` or `--feature grok:setup`.

## How to get to it (user POV)

Expand Down
45 changes: 24 additions & 21 deletions .claude/skills/verify-open-pstack/scripts/core.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { resolve } from 'node:path';
import registryData from '../features/registry.json';
import { recipe } from '../features/recipes.ts';
import { classify, completeEvidence, matches, newReceipt, requiredFeatures, requiredHarnesses, validateRegistry } from './core.ts';
import { HARNESSES, LIVE_HARNESSES, WRITER_PROVIDERS, type Receipt } from './types.ts';
import { HARNESSES, LIVE_HARNESSES, WRITER_PROVIDERS, type ChangedFile, type Receipt } from './types.ts';
import codexManifest from '../../../../plugins/pstack/.codex-plugin/plugin.json';
import claudeManifest from '../../../../plugins/pstack/.claude-plugin/plugin.json';

Expand All @@ -15,6 +15,7 @@ export function receipt(selfTest = false): Receipt {
r.selection = classify([{ filename: 'README.md' }], registry);
return r;
}
const withGrok = (features: string[]) => [...features, 'grok:dispatch', 'grok:setup'].sort();
const both = (...features: string[]): string[] => HARNESSES.flatMap(h => features.map(f => `${h}:${f}`)).sort();
export function evidence(r: Receipt): void {
for (const harness of requiredHarnesses(r)) {
Expand Down Expand Up @@ -52,7 +53,7 @@ describe('registry and ownership', () => {
test('markdown instructions are runtime', () => {
for (const filename of ['plugins/pstack/skills/architect/SKILL.md', 'plugins/pstack/skills/architect/references/guide.md']) {
const s = classify([{ filename }], registry);
expect(s.features).toEqual(both('skill-invocation:architect'));
expect(s.features).toEqual(withGrok(both('skill-invocation:architect')));
expect(s.noRuntime).toBe(false);
}
});
Expand All @@ -76,18 +77,20 @@ describe('registry and ownership', () => {
expect(requiredHarnesses(r)).toEqual(['claude', 'codex', 't3']);
expect(requiredFeatures(r, 't3')).toEqual(['dispatch']);
});
test('only the Grok surfaces reach grok:dispatch and grok:setup, and self-test never adds a Grok session', () => {
const reach = (filename: string) => classify([{ filename }], registry).features.filter(f => f.startsWith('grok:'));
test('every runtime ownership permits naming both Grok features; assets, version-only manifests and non-runtime paths do not', () => {
const reach = (file: ChangedFile) => classify([file], registry).features.filter(f => f.startsWith('grok:'));
for (const filename of ['plugins/pstack/skills/poteto-mode/references/provider-dispatch.md', 'plugins/pstack/skills/poteto-mode/references/codex-tools.md',
'plugins/pstack/.grok-plugin/plugin.json', '.claude/skills/verify-open-pstack/scripts/doctor.ts',
'plugins/pstack/grok-agents/poteto-agent.md', 'plugins/pstack/grok-agents/comment-sicko.md',
'plugins/pstack/.grok-plugin/plugin.json', 'plugins/pstack/grok-agents/poteto-agent.md', 'plugins/pstack/grok-agents/comment-sicko.md',
'plugins/pstack/skills/poteto-mode/references/model-catalog.md', 'plugins/pstack/skills/poteto-mode/SKILL.md',
'plugins/pstack/skills/poteto-mode/scripts/runner/types.ts', 'plugins/pstack/skills/poteto-mode/scripts/runner/registry/index.ts',
'plugins/pstack/skills/poteto-mode/scripts/runner/registry/render.ts']) expect(reach(filename)).toEqual(['grok:dispatch']);
expect(reach('.claude/skills/verify-open-pstack/scripts/isolation.ts')).toEqual(['grok:setup']);
for (const filename of ['plugins/pstack/skills/setup-pstack/SKILL.md', '.claude/skills/verify-open-pstack/scripts/grok.ts',
'.claude/skills/verify-open-pstack/scripts/harness.ts']) expect(reach(filename)).toEqual(['grok:dispatch', 'grok:setup']);
for (const filename of ['plugins/pstack/hooks/hooks.json', '.claude/skills/verify-open-pstack/scripts/verify.ts']) expect(reach(filename)).toEqual([]);
'plugins/pstack/skills/poteto-mode/scripts/runner/registry/render.ts', 'plugins/pstack/skills/setup-pstack/SKILL.md',
'.claude/skills/verify-open-pstack/scripts/io.ts', '.claude/skills/verify-open-pstack/scripts/grok.ts',
'.claude/skills/verify-open-pstack/scripts/a-new-helper.ts', 'plugins/pstack/skills/arena/references/a-new-reference.md',
'plugins/pstack/skills/poteto-mode/scripts/resolve-codex-transcript.ts']) expect(reach({ filename })).toEqual(['grok:dispatch', 'grok:setup']);
expect(reach({ filename: 'plugins/pstack/assets/logo.png' })).toEqual([]);
expect(reach({ filename: 'plugins/pstack/.claude-plugin/plugin.json', versionOnly: true })).toEqual([]);
expect(reach({ filename: '.mergify.yml' })).toEqual([]);
expect(() => classify([{ filename: 'plugins/pstack/unknown/file.ts' }], registry)).toThrow('Unmapped path');
const r = receipt(true);
r.runFeatures = ['grok:dispatch', 'grok:setup'];
expect(requiredHarnesses(r)).toEqual(['claude', 'codex', 'grok']);
Expand All @@ -105,7 +108,7 @@ describe('registry and ownership', () => {
});
test('poteto-mode SKILL.md also reaches the Claude agent that preloads it', () => {
const s = classify([{ filename: 'plugins/pstack/skills/poteto-mode/SKILL.md' }], registry);
expect(s.features).toEqual([...both('skill-invocation:poteto-mode'), 'claude:agent-preload:poteto-agent', 'grok:dispatch'].sort());
expect(s.features).toEqual(withGrok([...both('skill-invocation:poteto-mode'), 'claude:agent-preload:poteto-agent']));
});
const CATALOG = 'plugins/pstack/skills/poteto-mode/references/model-catalog.md';
test('catalog-only changes select catalog, setup and runner and no skill check', () => {
Expand All @@ -114,7 +117,7 @@ describe('registry and ownership', () => {
'plugins/pstack/skills/poteto-mode/scripts/runner/registry/models.ts']) {
const s = classify([{ filename }], registry);
expect(s.skills).toEqual([]);
expect(s.features).toEqual(filename === CATALOG ? [...both('catalog', 'runner', 'setup'), 'grok:dispatch'].sort() : both('catalog', 'runner', 'setup'));
expect(s.features).toEqual(withGrok(both('catalog', 'runner', 'setup')));
}
const PROVIDERS = 'plugins/pstack/skills/poteto-mode/scripts/runner/providers/';
for (const [filename, writers] of [
Expand All @@ -123,21 +126,21 @@ describe('registry and ownership', () => {
['amp.test.ts', 'writers:amp'], ['fixtures/amp/lockdown-settings.json', 'writers:amp'], ['dsh-preflight.yml', 'writers:dsh'],
]) {
expect([filename, classify([{ filename: `${PROVIDERS}${filename}` }], registry).features])
.toEqual([filename, both('catalog', 'runner', 'setup', writers!)]);
.toEqual([filename, withGrok(both('catalog', 'runner', 'setup', writers!))]);
}
});
test('a renamed or deleted catalog path keeps catalog ownership', () => {
for (const previous_filename of [CATALOG, 'plugins/pstack/agents/pstack-opus-max.md']) {
expect(classify([{ filename: 'docs/moved.md', previous_filename }], registry).features)
.toEqual(previous_filename === CATALOG ? [...both('catalog', 'runner', 'setup'), 'grok:dispatch'].sort() : both('catalog', 'runner', 'setup'));
.toEqual(withGrok(both('catalog', 'runner', 'setup')));
}
});
test('a catalog change mixed with a shared reference or a skill keeps their checks', () => {
const shared = classify([{ filename: CATALOG }, { filename: 'plugins/pstack/skills/poteto-mode/references/provider-dispatch.md' }], registry);
expect(shared.skills).toEqual([...registry.skills].sort());
for (const feature of both('catalog', 'setup', 'runner', 'shipped-tools')) expect(shared.features).toContain(feature);
const skill = classify([{ filename: 'plugins/pstack/agents/pstack-opus-max.md' }, { filename: 'plugins/pstack/skills/arena/SKILL.md' }], registry);
expect(skill.features).toEqual(both('catalog', 'runner', 'setup', 'skill-invocation:arena'));
expect(skill.features).toEqual(withGrok(both('catalog', 'runner', 'setup', 'skill-invocation:arena')));
});
test('an unlisted generated agent fails closed', () => {
expect(() => classify([{ filename: 'plugins/pstack/agents/pstack-retired-max.md' }], registry)).toThrow('Unmapped path');
Expand Down Expand Up @@ -202,14 +205,14 @@ describe('registry and ownership', () => {
test('bootstrap changes require its shipped tool consumers, not the unrelated runner', () => {
const s = classify([{ filename: 'plugins/pstack/skills/poteto-mode/scripts/bootstrap.ts' }], registry);
expect(s.noRuntime).toBe(false);
expect(s.features).toEqual(both('shipped-tools'));
expect(s.features).toEqual(withGrok(both('shipped-tools')));
});
test('the transcript resolver belongs to Reflect rather than unrelated shipped tools', () => {
const path = 'plugins/pstack/skills/poteto-mode/scripts/resolve-codex-transcript.ts';
for (const file of [{ filename: path }, { filename: path.replace('.ts', '') }, { filename: 'docs/removed-resolver.md', previous_filename: path }]) {
const s = classify([file], registry);
expect(s.skills).toEqual(['reflect']);
expect(s.features).toEqual(both('skill-invocation:reflect'));
expect(s.features).toEqual(withGrok(both('skill-invocation:reflect')));
}
expect(() => classify([{ filename: path.replace('.ts', '.py') }], registry)).toThrow('Unmapped path');
expect(classify([{ filename: path.replace('.ts', '.test.ts') }], registry).noRuntime).toBe(true);
Expand All @@ -228,7 +231,7 @@ describe('registry and ownership', () => {
const r = receipt(true);
r.selection = classify([{ filename: '.claude/skills/verify-open-pstack/scripts/verify.ts' }], registry);
expect(r.selection.noRuntime).toBe(false);
expect(r.selection.features).toEqual(both('project-skill'));
expect(r.selection.features).toEqual(withGrok(both('project-skill')));
evidence(r);
expect(() => completeEvidence(r)).not.toThrow();
});
Expand All @@ -252,7 +255,7 @@ describe('registry and ownership', () => {
test('nearby verifier documentation retains only project proof', () => {
for (const filename of ['.claude/skills/verify-open-pstack/features/README.md',
'.claude/skills/verify-open-pstack/features/skill-invocation.md']) {
expect(classify([{ filename }], registry).features).toEqual(both('project-skill'));
expect(classify([{ filename }], registry).features).toEqual(withGrok(both('project-skill')));
}
});
test('shared recipe expansion survives overlapping catalog ownership without broadening ordinary catalog paths', () => {
Expand All @@ -271,7 +274,7 @@ describe('registry and ownership', () => {
for (const filename of ['AGENTS.md', 'CLAUDE.md', 'tests/skill-collision-repro.sh', '.github/workflows/ci.yml', 'package.json']) {
const s = classify([{ filename }], registry);
expect(s.noRuntime).toBe(false);
expect(s.features).toEqual(both('project-skill'));
expect(s.features).toEqual(withGrok(both('project-skill')));
expect(classify([{ filename: 'docs/moved.md', previous_filename: filename }], registry).noRuntime).toBe(false);
}
});
Expand Down
22 changes: 7 additions & 15 deletions .claude/skills/verify-open-pstack/scripts/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,7 @@ const T3_DISPATCH_PATHS = [
'plugins/pstack/skills/setup-pstack/SKILL.md', '.claude/skills/verify-open-pstack/features/recipes.ts',
'.claude/skills/verify-open-pstack/scripts/harness.ts', '.claude/skills/verify-open-pstack/scripts/doctor.ts',
];
const GROK_TRANSPORT = '.claude/skills/verify-open-pstack/scripts/grok.ts';
const GROK_REACH: Readonly<Record<string, readonly string[]>> = {
'grok:dispatch': [...T3_DISPATCH_PATHS, GROK_TRANSPORT, 'plugins/pstack/.grok-plugin/plugin.json',
'plugins/pstack/grok-agents/poteto-agent.md', 'plugins/pstack/grok-agents/comment-sicko.md', 'plugins/pstack/skills/poteto-mode/SKILL.md',
'plugins/pstack/skills/poteto-mode/references/model-catalog.md', 'plugins/pstack/skills/poteto-mode/scripts/runner/types.ts',
'plugins/pstack/skills/poteto-mode/scripts/runner/registry/index.ts', 'plugins/pstack/skills/poteto-mode/scripts/runner/registry/render.ts'],
'grok:setup': ['plugins/pstack/skills/setup-pstack/SKILL.md', '.claude/skills/verify-open-pstack/features/recipes.ts',
'.claude/skills/verify-open-pstack/scripts/harness.ts', '.claude/skills/verify-open-pstack/scripts/isolation.ts', GROK_TRANSPORT],
};
const GROK_FEATURES = ['grok:dispatch', 'grok:setup'] as const;

export const VERSION_MANIFESTS: Readonly<Record<string, Harness>> = {
'plugins/pstack/.claude-plugin/plugin.json': 'claude', '.claude-plugin/marketplace.json': 'claude', 'plugins/pstack/.codex-plugin/plugin.json': 'codex',
Expand All @@ -41,6 +33,7 @@ export function classify(files: ChangedFile[], registry: Registry): Selection {
const versionOnly = new Set(files.filter(f => f.versionOnly && !f.previous_filename).map(f => f.filename));
const skills = new Set<string>(), features = new Set<string>();
const both = (...names: string[]): void => names.forEach(f => HARNESSES.forEach(h => features.add(`${h}:${f}`)));
const grok = (): void => GROK_FEATURES.forEach(f => features.add(f));
for (const path of paths) {
if (!path || path.startsWith('/') || path.split('/').includes('..')) throw new Error(`Unsafe path: ${path}`);
if (versionOnly.has(path) && Object.hasOwn(VERSION_MANIFESTS, path)) { features.add(`${VERSION_MANIFESTS[path]}:hook:startup`); continue; }
Expand All @@ -50,28 +43,27 @@ export function classify(files: ChangedFile[], registry: Registry): Selection {
features.add('codex:assets:codex'); covered = true;
}
if (T3_DISPATCH_PATHS.includes(path)) features.add('t3:dispatch');
for (const [feature, reach] of Object.entries(GROK_REACH)) if (reach.includes(path)) features.add(feature);
const sharedRecipe = path === '.claude/skills/verify-open-pstack/features/recipes.ts';
if (sharedRecipe) both('catalog', 'writers', ...WRITER_PROVIDERS.map(provider => `writers:${provider}`));
const catalog = registry.catalog.some(p => matches(path, p));
if (catalog) { both('catalog', 'setup', 'runner'); covered = true; }
if (catalog) { both('catalog', 'setup', 'runner'); grok(); covered = true; }
if (sharedRecipe || (!catalog && registry.shared.some(p => matches(path, p)))) {
registry.skills.forEach(s => skills.add(s));
both('setup', 'runner', 'shipped-tools', 'hook:startup');
features.add('claude:agent-preload:poteto-agent');
covered = true;
grok(); covered = true;
}
for (const [key, feature] of [['setup', 'setup'], ['runner', 'runner'], ['tools', 'shipped-tools'], ['project', 'project-skill']] as const) {
if (registry[key].some(p => matches(path, p))) { both(feature); covered = true; }
if (registry[key].some(p => matches(path, p))) { both(feature); grok(); covered = true; }
}
if (/^plugins\/pstack\/skills\/poteto-mode\/scripts\/resolve-codex-transcript(?:\.ts)?$/.test(path)) { skills.add('reflect'); covered = true; }
if (/^plugins\/pstack\/skills\/poteto-mode\/scripts\/resolve-codex-transcript(?:\.ts)?$/.test(path)) { skills.add('reflect'); grok(); covered = true; }
const provider = /^plugins\/pstack\/skills\/poteto-mode\/scripts\/runner\/providers\/(?:fixtures\/)?([a-z]+)?/.exec(path);
if (provider) both((WRITER_PROVIDERS as readonly string[]).includes(provider[1] ?? '') ? `writers:${provider[1]}` : 'writers');
const skill = /^plugins\/pstack\/skills\/([^/]+)\/(.+)$/.exec(path);
if (!catalog && skill && registry.skills.includes(skill[1]!)) {
const leaf = skill[2]!;
if (leaf === 'SKILL.md' || leaf.startsWith('references/') || leaf.startsWith('playbooks/')) {
skills.add(skill[1]!); covered = true;
skills.add(skill[1]!); grok(); covered = true;
}
if (skill[1] === 'poteto-mode' && leaf === 'SKILL.md') features.add('claude:agent-preload:poteto-agent');
}
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/verify-open-pstack/scripts/verify.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ describe('exact-head evidence publication', () => {

test('a runtime change runs only the named features, plus project-skill in both harnesses under self-test', async () => {
const f = fixture(true, true), receipt = await verify(f.options);
expect(receipt.selection.features).toEqual(['claude:skill-invocation:architect', 'codex:skill-invocation:architect']);
expect(receipt.selection.features).toEqual(['claude:skill-invocation:architect', 'codex:skill-invocation:architect', 'grok:dispatch', 'grok:setup']);
expect(receipt.runFeatures).toEqual(['claude:skill-invocation:architect']);
expect(receipt.installations.map(record => record.harness).sort()).toEqual([...HARNESSES]);
expect(receipt.observations.map(record => `${record.harness}/${record.feature}`).sort()).toEqual(['claude/project-skill', 'claude/skill-invocation:architect', 'codex/project-skill']);
Expand Down
Loading