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
15 changes: 10 additions & 5 deletions src/workspaces/context-injector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { fileURLToPath } from 'node:url';

import { afterEach, beforeEach, describe, expect, it } from 'vitest';

import { defaultPath } from '@/core/paths.js';
import { dataPath, defaultPath } from '@/core/paths.js';

import { injectWorkspaceContext } from './context-injector.js';
import type { TemplateMeta } from './template-registry.js';
Expand Down Expand Up @@ -74,10 +74,15 @@ describe('injectWorkspaceContext — MCP', () => {
});

describe('injectWorkspaceContext — persona', () => {
it('composes persona + separator + template CLAUDE.md into CLAUDE.md and AGENTS.md', async () => {
const persona = await readFile(defaultPath('persona.default.md'), 'utf8');
const templateMd = await readFile(join(CHAT_FILES, 'CLAUDE.md'), 'utf8');
const expected = `${persona}\n\n---\n\n${templateMd}`;
it('composes persona + separator + template instruction into CLAUDE.md and AGENTS.md', async () => {
// Mirror the injector's persona precedence: a live data/brain/persona.md
// override wins over the shipped default.
const personaPath = existsSync(dataPath('brain', 'persona.md'))
? dataPath('brain', 'persona.md')
: defaultPath('persona.default.md');
const persona = await readFile(personaPath, 'utf8');
const instruction = await readFile(join(CHAT_FILES, 'instruction.md'), 'utf8');
const expected = `${persona}\n\n---\n\n${instruction}`;

await injectWorkspaceContext({
template: makeTemplate({ injectPersona: true, filesDir: CHAT_FILES }),
Expand Down
15 changes: 9 additions & 6 deletions src/workspaces/context-injector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,16 @@ export async function injectWorkspaceContext(opts: {
}

if (template.injectPersona) {
// Compose `persona + "\n\n---\n\n" + <template>/CLAUDE.md`, byte-identical
// to the old `compose_persona_claude_md`. A template that asks for persona
// injection but ships no CLAUDE.md is a misconfiguration — let the readFile
// throw so the create fails loudly (matches the old `exit 4`).
// One neutral instruction source (`<template>/instruction.md`), composed
// with the persona, then written byte-identically to BOTH CLAUDE.md (Claude
// Code's filename) and AGENTS.md (Codex's). The CLIs disagree on the
// filename; we don't pick a side — we copy to each at injection. A template
// that asks for persona injection but ships no instruction.md is a
// misconfiguration — let the readFile throw so the create fails loudly
// (matches the old `compose_persona_claude_md` exit 4).
const persona = await resolvePersona();
const templateMd = await readFile(join(template.filesDir, 'CLAUDE.md'), 'utf8');
const composed = persona !== null ? `${persona}\n\n---\n\n${templateMd}` : templateMd;
const instruction = await readFile(join(template.filesDir, 'instruction.md'), 'utf8');
const composed = persona !== null ? `${persona}\n\n---\n\n${instruction}` : instruction;
await writeWorkspaceFile(dir, 'CLAUDE.md', composed);
await writeWorkspaceFile(dir, 'AGENTS.md', composed);
}
Expand Down
2 changes: 1 addition & 1 deletion src/workspaces/template-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export interface TemplateMeta {
* Launcher-owned context injection, post-bootstrap, gated per template
* (defaults preserve each template's pre-standardization behavior):
* injectMcp — write the standard OpenAlice `.mcp.json`
* injectPersona — compose Alice persona + this template's CLAUDE.md
* injectPersona — compose Alice persona + this template's instruction.md
* into CLAUDE.md / AGENTS.md
* bundledSkills — names under `default/skills/` to copy into the
* workspace's `.claude/skills` + `.agents/skills`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,12 @@ To verify the wiring on first attach:
Otherwise, use this workspace however you like. The CWD is its own git
repo (commits stay local), and any files you create or edit are scoped
to this workspace.

## Handing work back to the user

This workspace has an outbound channel to the user's Inbox (`inbox_push`).
When you finish something the user should see — a shortlist, a thesis, a
rotation snapshot, a decision you reached — push it to their inbox: the
file(s) you produced plus a short note on what it is and why it matters.
Don't make them come looking in the workspace; surface the result. (One-way
for now — they read the inbox; they don't reply through it.)
Loading