Skip to content

Commit 31e06e8

Browse files
elberrdclaude
andcommitted
feat: layout imp/ — runtime, HARNESS.md e iai.config.json numa pasta só
O instalador agora carimba tudo em imp/ (era fia/): FDAs, módulos, viewer, dados, imp/HARNESS.md e imp/iai.config.json. ai-docs/ permanece na raiz. Projetos legados migram automaticamente (migrateLegacyFiaLayout): rename, reescrita de caminhos em imp/, .pi/, .claude/, .cursor/, package.json e .gitignore, rechaveamento do manifest preservando shas, retomada pós-crash e merge quando o pipeline criou imp/ antes (addons). v2.0.0-alpha.2. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 5c8e222 commit 31e06e8

88 files changed

Lines changed: 5538 additions & 304 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

DOCS.md

Lines changed: 196 additions & 17 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 230 additions & 31 deletions
Large diffs are not rendered by default.

bin/create-iai.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,17 @@ if (flags.verify) {
5656
process.exit(ok ? 0 : 1);
5757
}
5858

59+
// --update-runtime: re-stamps the FIA/Pi runtime of an already-installed
60+
// project from this package version and exits (config/data/local edits kept).
61+
if (flags.updateRuntime) {
62+
const { runUpdateRuntime } = await import('../src/steps/update-runtime.js');
63+
const ok = await runUpdateRuntime(flags).catch((err) => {
64+
console.error(err?.stack || String(err));
65+
return false;
66+
});
67+
process.exit(ok ? 0 : 1);
68+
}
69+
5970
// The TERMINAL assistant is the default entry point: `npx impactus`
6071
// asks every decision right there and then executes. The web UI (building the
6172
// command by clicking in the browser) is opt-in via --ui — see lib/pipeline.js.

bin/imp.js

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
#!/usr/bin/env node
2+
// imp — the IMPACTUS Academy launcher. A thin brand wrapper, NOT a Pi fork:
3+
// imp init … → runs the impactus installer (bin/create-iai.js) in-place
4+
// imp update → updates impactus + Pi
5+
// imp [args] → hands everything else to the real `pi` binary (stdio
6+
// inherited), installing Pi first if it is missing.
7+
// Keeping Pi as the actual agent means `pi update`, Codex login and the
8+
// project-level .pi/ config all keep working unchanged.
9+
10+
// Node version gate — the `engines` field doesn't block `npx` execution, so
11+
// enforce it here with a clear message (before importing anything modern).
12+
const [major, minor] = process.versions.node.split('.').map(Number);
13+
if (major < 20 || (major === 20 && minor < 9)) {
14+
console.error(`imp requires Node.js >= 20.9 (you are on ${process.versions.node}).`);
15+
console.error('Update at https://nodejs.org and try again.');
16+
process.exit(1);
17+
}
18+
19+
const { readFile } = await import('node:fs/promises');
20+
const { fileURLToPath } = await import('node:url');
21+
const pc = (await import('picocolors')).default;
22+
23+
const pkg = JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8'));
24+
const INSTALLER = fileURLToPath(new URL('./create-iai.js', import.meta.url));
25+
26+
// ANSI Shadow "IMPACTUS" — 64 columns wide.
27+
const ART = [
28+
'██╗███╗ ███╗██████╗ █████╗ ██████╗████████╗██╗ ██╗███████╗',
29+
'██║████╗ ████║██╔══██╗██╔══██╗██╔════╝╚══██╔══╝██║ ██║██╔════╝',
30+
'██║██╔████╔██║██████╔╝███████║██║ ██║ ██║ ██║███████╗',
31+
'██║██║╚██╔╝██║██╔═══╝ ██╔══██║██║ ██║ ██║ ██║╚════██║',
32+
'██║██║ ╚═╝ ██║██║ ██║ ██║╚██████╗ ██║ ╚██████╔╝███████║',
33+
'╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚══════╝',
34+
];
35+
const ART_WIDTH = 64;
36+
37+
function banner() {
38+
const columns = process.stdout.columns ?? 80;
39+
if (process.stdout.isTTY && columns >= ART_WIDTH + 2) {
40+
console.log('');
41+
for (const line of ART) console.log(pc.cyan(line));
42+
const sub = 'A C A D E M Y';
43+
console.log(pc.bold(pc.cyan(' '.repeat(Math.floor((ART_WIDTH - sub.length) / 2)) + sub)));
44+
console.log(pc.dim(`imp v${pkg.version} — Pi + the IAI harness, one command`));
45+
console.log('');
46+
} else {
47+
console.log(`IMPACTUS Academy — imp v${pkg.version}`);
48+
}
49+
}
50+
51+
function helpText() {
52+
return `
53+
imp — the IMPACTUS Academy CLI (Pi + the IAI harness)
54+
55+
Usage:
56+
imp Start Pi in the current folder (installs Pi if missing)
57+
imp init [options] Install the harness/FIA here (same as npx impactus;
58+
all impactus flags work — see \`imp init --help\`)
59+
imp update Update impactus and Pi to the latest versions
60+
imp help Show this help
61+
imp --version Print the impactus version
62+
63+
Anything else is passed straight to Pi, e.g.:
64+
imp -p "prompt" One-shot prompt (headless)
65+
imp --continue Resume the last session
66+
67+
First time? In your project folder run \`imp init\`, then \`imp\` and type
68+
/login openai-codex to connect your ChatGPT subscription. Never log in to
69+
Anthropic inside Pi — Claude runs through the official \`claude\` CLI.
70+
`.trimStart();
71+
}
72+
73+
const [cmd, ...rest] = process.argv.slice(2);
74+
75+
// --version stays banner-free and machine-readable, same as the installer.
76+
if (cmd === '--version' || cmd === '-v') {
77+
console.log(pkg.version);
78+
process.exit(0);
79+
}
80+
81+
if (cmd === 'help' || cmd === '--help' || cmd === '-h') {
82+
banner();
83+
console.log(helpText());
84+
process.exit(0);
85+
}
86+
87+
if (cmd === 'init') {
88+
banner();
89+
const { runInherit } = await import('../src/lib/proc.js');
90+
const r = await runInherit(process.execPath, [INSTALLER, ...rest]);
91+
process.exit(r.exitCode);
92+
}
93+
94+
if (cmd === 'update') {
95+
banner();
96+
const { runInherit } = await import('../src/lib/proc.js');
97+
const { hasPi, ensurePiReady } = await import('../src/lib/pi-auth.js');
98+
99+
console.log(`Updating impactus (npm install -g ${pkg.name}@latest)…`);
100+
const up = await runInherit('npm', ['install', '-g', `${pkg.name}@latest`]);
101+
if (!up.ok) {
102+
console.error(`Could not update impactus. Run it manually: npm install -g ${pkg.name}@latest`);
103+
console.error('If npm printed EACCES, reinstall Node.js in your user account (https://nodejs.org) — never use sudo.');
104+
}
105+
106+
try {
107+
if (await hasPi()) {
108+
console.log('Updating Pi (pi update)…');
109+
await runInherit('pi', ['update']);
110+
} else {
111+
await ensurePiReady(); // installs Pi with the friendly EACCES guidance
112+
}
113+
} catch (err) {
114+
console.error(err?.message || String(err));
115+
process.exit(1);
116+
}
117+
console.log('Done.');
118+
process.exit(up.ok ? 0 : 1);
119+
}
120+
121+
// Default: launch Pi with every argument passed through untouched.
122+
// Banner only when a human is watching: with stdout piped/captured
123+
// (`imp -p … > file`, scripts, another process driving imp) Pi's output
124+
// must arrive exactly as `pi` would produce it.
125+
if (process.stdout.isTTY) banner();
126+
const { runInherit } = await import('../src/lib/proc.js');
127+
const { hasPi, ensurePiReady } = await import('../src/lib/pi-auth.js');
128+
129+
// Only install when missing — no network version check on every launch
130+
// (`imp update` and the installer already keep Pi fresh).
131+
if (!(await hasPi())) {
132+
try {
133+
await ensurePiReady();
134+
} catch (err) {
135+
console.error(err?.message || String(err));
136+
process.exit(1);
137+
}
138+
console.log(pc.dim('Tip: inside Pi, type /login openai-codex to connect your ChatGPT subscription.'));
139+
}
140+
141+
const args = cmd === undefined ? [] : [cmd, ...rest];
142+
const r = await runInherit('pi', args);
143+
process.exit(r.exitCode);

docs/specialists-plan.md

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# Specialists — analysis and plan
2+
3+
> **Decision taken (Aug 13, 2026) — the first concrete instance of this plan.**
4+
> The `frontend-design` skill (anthropics/skills) that rode into both template
5+
> lockfiles undecided was the "third design authority" conflict below. Instead
6+
> of keeping it installed as a competing skill, its general rules were
7+
> **absorbed** into the house `design-system` skill as
8+
> `references/design-direction.md` (adapted to our registry/theme system, with
9+
> golden rule 8 pointing at it), and the entry was removed from
10+
> `live1/skills-lock.json` + `live2/skills-lock.json`. The absorption follows
11+
> the CLI's differentiator — markdown states the rule, code checks it: the new
12+
> `theme_tokens` warn in `fia-launch-check.mjs` flags hardcoded hex in UI
13+
> components, which is the enforceable core of that skill's guidance. This is
14+
> the template for future cases: **vendor-specific knowledge stays an official
15+
> skill; general-taste/process knowledge gets absorbed into a house skill (as a
16+
> `references/` file) plus a deterministic check where one exists.** One-off
17+
> needs use `npx skills use <pkg>@<skill>` — load without installing.
18+
19+
Question raised after studying Specsfy: they ship "especialistas" — optional
20+
knowledge packs for a technology (Laravel, React, Postgres, Docker, security,
21+
observability…), living in a GitHub catalog, installed on demand. Do we have
22+
something equivalent, and would adding it collide with what already exists?
23+
24+
**Short answer: we have the substance, we lack the discovery — and the standard
25+
we already use solves it, so there is nothing to invent.** What needs designing
26+
is curation and precedence, not machinery.
27+
28+
## What Specsfy's specialists actually are
29+
30+
- ~25 technology skills in their own catalog, grouped by domain (backend/data,
31+
frontend, interface, platform, quality, technical design, engineering).
32+
- `specsfy skills detect` scans the project and *recommends* without installing;
33+
the user then picks explicitly with `specsfy skills add`; installs are
34+
recorded in `skills-lock.json`.
35+
- They plug into workflow stages (backlog identifies the need, tasks applies the
36+
checklist, implement executes to the stack) but — their own docs are explicit
37+
— a specialist "does not create specs nor approve gates". They add knowledge,
38+
never authority.
39+
40+
That last constraint is the good part of the idea and the part worth copying.
41+
42+
## What we already have
43+
44+
| Layer | What it is | How it arrives |
45+
|---|---|---|
46+
| **House skills** | 5 harness skills — `tdd`, `frontend-profissional`, `backend-profissional`, `design-system`, `security` | Always installed, from the harness. Process and quality standards, opinionated for our stack. |
47+
| **Official vendor skills** | Convex, Clerk, Cloudflare/wrangler, Stripe, Sentry, Resend | `npx skills add <source>` per chosen tech/addon, recorded in `skills-lock.json` |
48+
| **Generated tech docs** | `ai-docs/apis/<tech>.md` (with a Production section) | `/stack`, for technologies with no official skill |
49+
| **Project skills** | e.g. the Asaas skill shipped in the template | Ships with the template |
50+
51+
So the "specialist" role is filled three times over. Where it overlaps, **ours
52+
is better**: an official Stripe or Sentry skill written by the vendor beats a
53+
third party's summary of the same product, and it is versioned by whoever owns
54+
the API.
55+
56+
What we genuinely lack:
57+
58+
1. **Discovery** — no way for a student to see what packs exist, or to ask "is
59+
there something for Playwright?". `/stack` decides for the stack layers and
60+
nothing else.
61+
2. **Update** — installs are recorded in `skills-lock.json` and then frozen. No
62+
student ever runs `skills update`.
63+
3. **Off-stack knowledge** — a pack that is not tied to a stack layer (a11y,
64+
performance, observability, testing-in-CI) has no entry point at all.
65+
4. **Restore** — after a fresh clone, nothing re-installs from the lock file.
66+
67+
## The mechanism already exists — measured, not assumed
68+
69+
The `skills` CLI we already invoke covers every one of those gaps:
70+
71+
| Gap | Command |
72+
|---|---|
73+
| Discovery | `npx skills find <query>` · `npx skills find react --owner vercel` |
74+
| See what's installed | `npx skills list --json` |
75+
| Update | `npx skills update [name]` |
76+
| Restore after clone | `npx skills experimental_install` |
77+
| **Load without installing** | `npx skills use <pkg>@<skill>` — emits the prompt for ONE skill, nothing written to disk |
78+
79+
That last one is precisely the shape the idea described — knowledge that lives
80+
in GitHub and is *loaded* when needed rather than permanently installed. It is
81+
already there; we have never told a student it exists.
82+
83+
So: **do not build a specialists subsystem.** Build curation and a door.
84+
85+
## Conflicts to respect (the actual analysis)
86+
87+
Five real ones, in order of how much damage they do if ignored.
88+
89+
**1. Skills run with full agent permissions.** The CLI itself prints "Review
90+
skills before use; they run with full agent permissions" after every install.
91+
Our students are beginners on a paid course; pointing them at open community
92+
search is a supply-chain surface with their credentials and their repo behind
93+
it. **Rule: we ship a curated allowlist. `skills find` is shown as an advanced
94+
escape hatch, with the warning repeated in our own words, never as the default
95+
path.**
96+
97+
**2. Context bloat.** Every installed skill's `description` is loaded so the
98+
agent can decide whether to open it. Fifteen specialists is fifteen
99+
descriptions competing with our own routing table on every turn — and our
100+
harness already spends that budget on 5 house skills plus the workflow routers.
101+
**Rule: recommend, never bulk-install; cap what we suggest per project; prefer
102+
`skills use` for one-off questions over a permanent install.**
103+
104+
**3. Authority collision with the house skills.** `backend-profissional` and
105+
`security` are opinionated for Convex/Clerk. A Postgres or Laravel pack will
106+
contradict them, and an agent has no way to know which wins. AGENTS.md already
107+
carries the seed of the rule ("the professional skills assume the recommended
108+
stack; on other stacks the reference is `ai-docs/apis/<tech>.md`"). **Rule to
109+
make explicit: house skills win on process, quality and security posture;
110+
external packs win on the API details of their own technology. A pack never
111+
approves a gate, never changes the task flow, never overrides the design-system
112+
registry or the spec/coverage gates.** (Same boundary Specsfy draws, and for
113+
the same reason.)
114+
115+
**4. Writes during an FDA are reverted.** Installing a skill writes
116+
`.agents/skills/`, `.claude/skills/`, `.pi/skills/` and `skills-lock.json`. The
117+
FDA permission gate attributes any external change to the running phase and
118+
rolls it back. **Rule: skill installation is interactive-only — never inside a
119+
`/task`, `/goal` or any FDA run.** Verified safe on the other side:
120+
`--update-runtime` only touches `.pi/skills/fia/`, so a third-party pack in
121+
`.pi/skills/<other>` is never clobbered.
122+
123+
**5. Name collisions with the harness.** Our house skills are the single source
124+
([[harness-fonte-unica]]); a pack publishing a skill called `security` or
125+
`design-system` would land beside ours with the same name in different
126+
directories. **Rule: before installing, check the name against the house set
127+
and refuse with an explanation rather than shadowing.**
128+
129+
## The plan
130+
131+
Four pieces, small, in order. None of them is a new subsystem.
132+
133+
**1. A curated catalog** (`src/config.js`, data only — same shape as
134+
`OPTIONAL_SKILLS`): recommended packs grouped by domain, each with source,
135+
skill names, one line on when it helps, and which stack it assumes. Seeded from
136+
what we can vouch for: the official vendor packs we already install, plus
137+
`vercel-labs/agent-skills` for the deploy/perf side. Growing it is a data edit,
138+
not code.
139+
140+
**2. `/skills` — the door** (harness + Pi). Read-only by default: shows what is
141+
installed (`skills list`), what the catalog recommends **for this project's
142+
stack manifest** — we already know the stack from `ai-docs/stack.md`, so we do
143+
not need Specsfy's scanner — and what is out of date. Installing is an explicit
144+
confirmation per pack, with conflicts 1/3/5 checked first. Never runs inside an
145+
FDA (conflict 4).
146+
147+
**3. Precedence written down**: one AGENTS.md convention encoding the rule from
148+
conflict 3, plus a line in each house skill saying it outranks external packs on
149+
its own subject.
150+
151+
**4. Restore + update in the lifecycle**: `npx skills experimental_install` in
152+
the post-clone instructions, and a `skills update` suggestion in `/status` when
153+
the lock file is older than N days. Cheap, and it is the gap Specsfy actually
154+
closed that we did not.
155+
156+
## What NOT to do
157+
158+
- Do not fork or re-host other people's skills into our templates — the
159+
`skills-lock.json` hash is the integrity story; copying breaks it and makes us
160+
responsible for content we do not maintain.
161+
- Do not auto-install on detection. The choice is the student's, and the
162+
permission surface (conflict 1) is the reason.
163+
- Do not give packs any authority in the workflow: no gate approval, no
164+
registry override, no task-flow changes.
165+
- Do not write our own competing knowledge docs for a technology that already
166+
publishes an official skill — `ai-docs/apis/<tech>.md` exists exactly for the
167+
technologies that do not.

0 commit comments

Comments
 (0)