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, `provider-dispatch.md`, `codex-tools.md`, `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`. 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`.

## How to get to it (user POV)

Expand Down
16 changes: 10 additions & 6 deletions .claude/skills/verify-open-pstack/scripts/core.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,15 @@ describe('registry and ownership', () => {
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:'));
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']) expect(reach(filename)).toEqual(['grok:dispatch']);
'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/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/skills/poteto-mode/references/model-catalog.md', 'plugins/pstack/skills/poteto-mode/SKILL.md',
'plugins/pstack/hooks/hooks.json', '.claude/skills/verify-open-pstack/scripts/verify.ts']) expect(reach(filename)).toEqual([]);
for (const filename of ['plugins/pstack/hooks/hooks.json', '.claude/skills/verify-open-pstack/scripts/verify.ts']) expect(reach(filename)).toEqual([]);
const r = receipt(true);
r.runFeatures = ['grok:dispatch', 'grok:setup'];
expect(requiredHarnesses(r)).toEqual(['claude', 'codex', 'grok']);
Expand All @@ -102,7 +105,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'].sort());
expect(s.features).toEqual([...both('skill-invocation:poteto-mode'), 'claude:agent-preload:poteto-agent', 'grok:dispatch'].sort());
});
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 @@ -111,7 +114,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(both('catalog', 'runner', 'setup'));
expect(s.features).toEqual(filename === CATALOG ? [...both('catalog', 'runner', 'setup'), 'grok:dispatch'].sort() : both('catalog', 'runner', 'setup'));
}
const PROVIDERS = 'plugins/pstack/skills/poteto-mode/scripts/runner/providers/';
for (const [filename, writers] of [
Expand All @@ -125,7 +128,8 @@ describe('registry and ownership', () => {
});
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(both('catalog', 'runner', 'setup'));
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'));
}
});
test('a catalog change mixed with a shared reference or a skill keeps their checks', () => {
Expand Down
5 changes: 4 additions & 1 deletion .claude/skills/verify-open-pstack/scripts/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ const T3_DISPATCH_PATHS = [
];
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'],
'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'],
Comment thread
github-actions[bot] marked this conversation as resolved.
Resolved
'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],
};
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/verify-open-pstack/scripts/grok.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { existsSync } from 'node:fs';
import { copyFile, open, readdir, realpath } from 'node:fs/promises';
import { dirname, join, resolve } from 'node:path';
import { track, treeHash } from './io.ts';
import { grokHome, track, treeHash } from './io.ts';
import type { SessionRecord } from './types.ts';

export const GROK_PARENT = { model: 'grok-4.7', effort: 'low' } as const;
Expand Down Expand Up @@ -88,7 +88,7 @@ export async function grokSession(options: Options): Promise<{ exitCode: number;
child.stdin.end();
const exitCode = await child.exited;
await reader;
const sessions = join(options.env.GROK_HOME ?? join(options.env.HOME!, '.grok'), 'sessions');
const sessions = join(grokHome(options.env), 'sessions');
const folder = (await readdir(sessions)).find(cwd => existsSync(join(sessions, cwd, sessionId, 'summary.json')));
if (!folder) throw new Error('grok-session-record-missing');
const record = join(sessions, folder, sessionId);
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/verify-open-pstack/scripts/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { copyFile, mkdir, open, readdir, readFile, realpath, stat, writeFile } f
import { basename, join } from 'node:path';
import { CLAUDE_TOOLS, recipe, type Fixture } from '../features/recipes.ts';
import { requiredFeatures, requiredHarnesses } from './core.ts';
import { command, isolatedEnv, retainedFile, save, session, treeHash, type Command, type Session } from './io.ts';
import { command, grokHome, isolatedEnv, retainedFile, save, session, treeHash, type Command, type Session } from './io.ts';
import { doctor, t3Binary } from './doctor.ts';
import { grokSession, parseGrok } from './grok.ts';
import { assertCodexAuth, linkCodexAuth, linkMuseConfig, removeCodexHome, restoreSetup, snapshotSetup, type SetupSnapshot } from './isolation.ts';
Expand Down Expand Up @@ -198,7 +198,7 @@ export class MacDriver implements Driver {
const slug = feature.replace(/[^a-z0-9-]/g, '-'), dir = join(home, 'fixtures', slug), records = join(receipt.artifactRoot, 'sessions', harness, slug);
for (const path of [dir, records]) await mkdir(path, { recursive: true, mode: 0o700 });
const fixture: Fixture = { harness, dir, workspace, location: installation.location, run: this.candidate(home),
configHome: harness === 'codex' ? env.CODEX_HOME! : harness === 'grok' ? env.GROK_HOME ?? join(env.HOME!, '.grok') : env.CLAUDE_CONFIG_DIR ?? join(env.HOME!, '.claude') };
configHome: harness === 'codex' ? env.CODEX_HOME! : harness === 'grok' ? grokHome(env) : env.CLAUDE_CONFIG_DIR ?? join(env.HOME!, '.claude') };
const assertions: string[] = [], evidence: string[] = [];
if (setupFeature(feature)) this.setup = await snapshotSetup();
try {
Expand Down
5 changes: 4 additions & 1 deletion .claude/skills/verify-open-pstack/scripts/io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ export const session: Session = async (args, options) => {
} finally { await stderr.close(); }
} finally { await stdout.close(); }
};
export function grokHome(env: Readonly<Record<string, string | undefined>>): string {
return env.GROK_HOME || join(env.HOME!, '.grok');
}
export function isolatedEnv(state: string, _harness?: 'claude' | 'codex'): Record<string, string> {
if (!isAbsolute(state)) throw new Error('Candidate state must be an absolute run-owned directory');
const { HOME, USER, LOGNAME } = process.env;
Expand All @@ -69,7 +72,7 @@ export function isolatedEnv(state: string, _harness?: 'claude' | 'codex'): Recor
GIT_CONFIG_GLOBAL: '/dev/null', GIT_CONFIG_SYSTEM: '/dev/null', GIT_CONFIG_NOSYSTEM: '1',
GIT_CONFIG_COUNT: '1', GIT_CONFIG_KEY_0: 'credential.helper', GIT_CONFIG_VALUE_0: '',
...(process.env.CLAUDE_CONFIG_DIR !== undefined ? { CLAUDE_CONFIG_DIR: process.env.CLAUDE_CONFIG_DIR } : {}),
...(process.env.GROK_HOME !== undefined ? { GROK_HOME: process.env.GROK_HOME } : {}),
...(process.env.GROK_HOME ? { GROK_HOME: process.env.GROK_HOME } : {}),
CODEX_HOME: join(state, '.codex') };
}
export async function save(path: string, value: unknown): Promise<void> {
Expand Down
13 changes: 13 additions & 0 deletions .claude/skills/verify-open-pstack/scripts/isolation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,19 @@ describe('setup-only snapshot and restoration', () => {
expect(await snapshotSetup()).toHaveLength(7);
});

test('an empty GROK_HOME snapshots the default Grok sheet, as setup resolves it', async () => {
const { root } = await fixture();
process.env.GROK_HOME = '';
const sheet = join(root, '.grok/rules/pstack-models.md');
await mkdir(join(root, '.grok/rules'), { recursive: true });
await writeFile(sheet, 'operator sheet');
const snapshot = await snapshotSetup();
expect(snapshot.map(entry => entry.path)).toContain(sheet);
await writeFile(sheet, 'setup mutation');
await restoreSetup(snapshot);
expect(await readFile(sheet, 'utf8')).toBe('operator sheet');
});

test('restores the Grok sheet under GROK_HOME byte for byte', async () => {
const { root } = await fixture();
process.env.GROK_HOME = join(root, 'daily-grok');
Expand Down
3 changes: 2 additions & 1 deletion .claude/skills/verify-open-pstack/scripts/isolation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { lstat, mkdir, readFile, readlink, realpath, rm, stat, symlink, writeFile } from 'node:fs/promises';
import { isAbsolute, join, resolve } from 'node:path';
import { grokHome } from './io.ts';

function codexAuth(): string {
return resolve(process.env.CODEX_HOME ?? join(process.env.HOME!, '.codex'), 'auth.json');
Expand Down Expand Up @@ -61,7 +62,7 @@ export async function snapshotSetup(): Promise<SetupSnapshot> {
const directories = new Set([join(process.env.HOME!, '.claude'), join(process.env.HOME!, '.codex'),
process.env.CLAUDE_CONFIG_DIR, process.env.CODEX_HOME].filter((directory): directory is string => !!directory).map(directory => resolve(directory)));
const paths = [...directories].flatMap(directory => ['pstack-models.md', 'CLAUDE.md', 'AGENTS.md'].map(name => join(directory, name)));
paths.push(join(resolve(process.env.GROK_HOME ?? join(process.env.HOME!, '.grok')), 'rules/pstack-models.md'));
paths.push(join(resolve(grokHome(process.env)), 'rules/pstack-models.md'));
const snapshot: SetupSnapshot = [];
for (const path of paths) {
const link = (await lstat(path).catch(() => undefined))?.isSymbolicLink() ? await readlink(path) : undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Reflect never edits a skill inside the plugin cache, `<config-home>/plugins/cach
| --- | --- | --- |
| Claude Code | `.claude/skills/<skill>/` | `<config-home>/skills/<skill>/` |
| Codex | `.agents/skills/<skill>/` | `$HOME/.agents/skills/<skill>/` |
| Grok | `.grok/skills/<skill>/` | `<config-home>/skills/<skill>/` |

The copy registers under its plain name beside the plugin's `pstack:<skill>`, and does not replace it. In the copy, rewrite each relative link that leaves the skill folder, such as `../poteto-mode/`, to the absolute path of that folder in the installed plugin.

Expand Down
Loading