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
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@ DATABASE_URL=postgresql://chopin:chopin@127.0.0.1:5432/chopin?sslmode=disable
AGENT=on
# With HARNESS=pi, use an ID from Pi's catalog, preferably provider-qualified
# (for example github-copilot/gpt-5.6-luna); Pi silently substitutes its default
# model for an ID it does not know, including gpt-6-luna.
# model for an ID it does not know, including gpt-6-luna. HARNESS=atomic requires
# a provider/model ID from Atomic's catalog (for example
# vercel-ai-gateway/anthropic/claude-sonnet-4.6) and fails a turn on any other.
MODEL=gpt-6-luna
HARNESS=copilot-sdk
# Auth mode forwarded to the selected harness. The current copilot-sdk adapter
# uses each owner's token and does not consume it. Host-login fallback modes
# such as "auto" require SERVER_HOST to bind only to loopback. HARNESS=pi
# requires this to be set explicitly (auto, openai, anthropic, custom, or
# ai-gateway); only ai-gateway is allowed on a non-loopback SERVER_HOST.
# HARNESS=atomic requires auto (the host's Atomic login and environment keys,
# loopback only) or ai-gateway (AI_GATEWAY_API_KEY, any bind).
#HARNESS_AUTH=
BACKGROUND_JOBS=on
WEB_RESEARCH=on
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,15 @@ and tool vocabulary remain optimized for planning.
- The first eligible person to invoke the Planner or start a model-backed
research request supplies the GitHub App user token used for that channel
and, under the default `copilot-sdk` harness, the Copilot entitlement. With
`HARNESS=pi`, model access comes from the operator's `HARNESS_AUTH` instead.
`HARNESS=pi` or `HARNESS=atomic`, model access comes from the operator's
`HARNESS_AUTH` instead.
A server restart clears every session and releases that ownership. A
returning browser in local device mode can restore a new session, but does
not reclaim Planner ownership.
- Document and Chat context, along with repository material selected by
the Planner, is sent to the harness's model provider during a turn (GitHub
Copilot by default; under `HARNESS=pi`, the provider chosen by
`HARNESS_AUTH`). Model-backed background jobs also send job-specific private
Copilot by default; under `HARNESS=pi` or `HARNESS=atomic`, the provider
chosen by `HARNESS_AUTH`). Model-backed background jobs also send job-specific private
material, including context loaded during execution, to isolated workers on
the same harness. The public research worker receives
only the exact submitted brief, but may derive or refine the queries it sends
Expand Down
1 change: 1 addition & 0 deletions apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@ai-sdk/harness-pi": "catalog:harness",
"@ai-sdk/mcp": "catalog:harness",
"@ai-sdk/sandbox-just-bash": "catalog:harness",
"@bastani/atomic": "catalog:harness",
"@earendil-works/pi-coding-agent": "catalog:harness",
"@chopin/dialect": "workspace:*",
"@chopin/protocol": "workspace:*",
Expand Down
13 changes: 13 additions & 0 deletions apps/server/src/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,19 @@ describe("configuration", () => {
.toMatchObject({ harness: "pi", model: "openai/gpt-5.6" });
});

it("requires an explicit provider/model MODEL under the atomic harness", () => {
expect(() => configured({ HARNESS: "atomic", HARNESS_AUTH: "auto" }))
.toThrow("MODEL is required when HARNESS=atomic");
expect(configured({
HARNESS: "atomic",
HARNESS_AUTH: "ai-gateway",
MODEL: "vercel-ai-gateway/anthropic/claude-sonnet-4.6",
})).toMatchObject({
harness: "atomic",
model: "vercel-ai-gateway/anthropic/claude-sonnet-4.6",
});
});

it("requires a valid PostgreSQL URL", () => {
expect(() => configured({ DATABASE_URL: undefined })).toThrow("DATABASE_URL is required");
expect(() => configured({ DATABASE_URL: "https://database.test" })).toThrow("PostgreSQL URL");
Expand Down
9 changes: 6 additions & 3 deletions apps/server/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,15 @@ export type Config = {
const DEFAULT_PORT = 8787;
const DEFAULT_MODEL = "gpt-6-luna";

/** The default is a Copilot model ID. Pi resolves IDs against its own catalog,
* so a Pi deployment must name its model rather than inherit one Pi lacks. */
/** The default is a Copilot model ID. Pi and Atomic resolve IDs against their
* own catalogs, so those deployments must name a model rather than inherit one
* the catalog lacks. */
function model(harness: string): string {
let configured = process.env.MODEL;
if (configured) return configured;
if (harness === "pi") throw new Error("MODEL is required when HARNESS=pi");
if (harness === "pi" || harness === "atomic") {
throw new Error(`MODEL is required when HARNESS=${harness}`);
}
return DEFAULT_MODEL;
}
export function harnessSelection(): Pick<Config, "host" | "harness" | "harnessAuth"> {
Expand Down
Loading
Loading