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
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ monitoring and informs a model when an observed event provides useful work.
Installation defaults for GitHub accounts, AI accounts, roles, and selections
are unconfigured (`NULL`). Add them explicitly through configuration, with no
fixed count. See DESIGN.md §19.8 and docs/github-accounts.md for the implemented
GitHub configuration, remaining ambient-`gh` gaps (such as `agent a38`
visibility lookup), and the AI/role configuration gap.
GitHub configuration, and docs/ai-accounts.md for AI profiles, named roles and
explicit launch/usage selections. A38 visibility lookup requires a configured
GitHub session unless visibility is explicitly supplied.

Draft publication is immediate after the first signed task commit; see the
lifecycle. A draft plus local tests is not done. Ready for review is signed
Expand Down
35 changes: 24 additions & 11 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,14 +463,23 @@ Owned-row runtime fields (start/stop set control and tmux; `keep-working` may al
"rows": 24,
"provider": "grok",
"grok_session_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"model": "grok-4.6",
"model": "operator-selected-model",
"keep_working": { "standing_sent": true }
}
```

Start sets `control=attached` and the tmux name. Stop sets `control=stopped` and keeps the name. `agent session keep-working` updates `runtime.keep_working.standing_sent` on idle ticks so the standing instruction is sent once. Session `status` (`active` / `closed`) is separate; `session close` stays as it is.

**Grok Build launch** (`--provider grok` or control `{provider: "grok"}`) is not the store session id. The Grok CLI `--session-id` flag accepts only a UUID (`8-4-4-4-12`). A caller-chosen session id (including a ULID) is never passed through. First start mints `runtime.grok_session_id` and runs `grok --always-approve --session-id <uuid> --model grok-4.6`. Later starts, if that field is set, run `grok --always-approve --resume <uuid> --model grok-4.6`. An empty model becomes `grok-4.6`; it must not inherit a Claude default. The pane is started with `env -u ANTHROPIC_API_KEY -u CLAUDECODE -u CLAUDE_CODE_ENTRYPOINT` so Claude credentials do not leak into the Grok process. `--provider` and `--cmd` cannot be combined.
**Grok Build launch** (`--provider grok` or control `{provider: "grok"}`) resolves
an explicit interactive role from `ai-accounts.json`. The model and provider
profile directory are required configuration; there is no built-in model.
The CLI accepts only a UUID, so first start creates `runtime.grok_session_id`.
A later start may resume that ID only with the same recorded AI binding
(role, account, provider, model, access and configuration-directory hash).
Changing that binding, or adopting an old unbound ID, requires a new session.
Provider credential environment variables are cleared in the child process,
and `GROK_HOME` selects the configured profile. `--provider` and `--cmd` cannot
be combined; `--model`, when supplied, must match the configured role.

**Vendors remain `grok` | `codex`.** A process running inside a tmux pane is not a store vendor. There is no `vendor=claude` and no shell-string tmux driver: the runtime invokes `tmux` with argv lists only. `runtime.provider` is launch metadata, not a review-gate vendor.

Expand Down Expand Up @@ -658,14 +667,18 @@ executor verifies the selected login and never falls back to an ambient login
or a different configured account. GitHub execution identities do not change the
device's hub identity or transfer ownership of store rows.

**Remaining implementation boundary:** this GitHub configuration does not cover
every CLI path that may invoke `gh`. In particular, `agent a38` visibility
lookup still runs ambient host `gh repo view` when `--private` is omitted
(`src/agent_cli/a38.py`), without loading `github-accounts.json` or a session
binding. This manifest also does not yet implement configurable AI accounts or
user-defined roles. The role/vendor lists and model choices in `lane.py`, and
the Grok default in `runtime.py`, still contain fixed values. They must not be
presented as satisfying the complete empty-default configuration requirement.
[AI configuration](docs/ai-accounts.md) supplies arbitrarily named account
profiles and roles, explicit models/access and session-to-role bindings. It is
used by lane launches, interactive Grok starts and optional Grok usage reads.
Absent configuration authorizes no AI launch. Fixed workflow kinds and the
Grok/Codex provider adapters are protocol capabilities, not installed account
or role selections. A38 visibility lookup uses an explicitly bound GitHub
session, or operator-supplied visibility without a GitHub lookup.

The standalone PR guard retains its explicit workflow-token configuration.
Trusted script APIs and raw terminal commands are not a sandbox. Complete
issue-to-PR orchestration and technical restrictions on model tools remain
separate work as documented in §19.7.

## 20. Refused: hub as a coding control plane

Expand Down Expand Up @@ -808,7 +821,7 @@ Phase 1 is this loop plus a backlog. Smarter questions are later.

## 23. Document history

Recorded from the design thread that specified realtime team visibility, rejected a central write database and a mesh, rejected embedding the hub in the existing public API, chose GitHub login + git teams, and split the work into `agent` + `agent-core`. Control: local tmux ownership, hub control frames, ephemeral terminal bytes. Grok launch: own UUID in `runtime.grok_session_id`, `--resume` on later starts, default model `grok-4.6`, no Claude environment in the pane.
Recorded from the design thread that specified realtime team visibility, rejected a central write database and a mesh, rejected embedding the hub in the existing public API, chose GitHub login + git teams, and split the work into `agent` + `agent-core`. Control: local tmux ownership, hub control frames, ephemeral terminal bytes. Grok launch: own UUID in `runtime.grok_session_id`, `--resume` on later starts, the historical default model (now replaced by explicit AI configuration), no Claude environment in the pane.

This revision replaces default complete pull with own events + inbox/subscription snapshots, moves the local engine to PostgreSQL, requires a session row, adds the `activity` catalog and opt-in skills, and adds session-addressed mail with a TUI knock of `da ist Post id <uuid>` only.

Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ Accounts and roles must start unconfigured (`NULL`); see
execution accounts and session bindings explicitly in
[`github-accounts.json`](docs/github-accounts.md) for the executors that load
it. There is no default GitHub account or fallback to the host login on those
paths. Some legacy CLI paths still use ambient host `gh` (for example
`agent a38` visibility lookup when `--private` is omitted); that gap is named
in the design and the accounts document. AI-account and role configuration
remain separate implementation work, as recorded in the design.
paths. A38 visibility lookup likewise requires an explicitly configured
`--github-session`, unless `--private` or `--public` supplies the report visibility.
[AI accounts and roles](docs/ai-accounts.md) configure provider profiles, models,
access and session bindings without built-in selections. `agent lane run` needs
`--session`; `agent run` uses its task session. Interactive Grok starts require
an interactive role binding. Automatic Grok usage reads are disabled until
`usage_session` is explicitly configured.

## Install

Expand Down
2 changes: 1 addition & 1 deletion docs/a38.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ agent a38 run --repo . --policy /tmp/a38-run/policy.json \
--output /tmp/a38-run/report.md --logs-dir /tmp/a38-run/logs --private
```

The runner identifies the GitHub repository from `origin` by default; for a fork, pass `--repository OWNER/NAME` with the PR target repository. It queries that repository's visibility through `gh`; explicit `--private` or `--public` selects visibility when needed. A38 checks that visibility against the actual repository. The runner executes the complete job list sequentially, records each command's result, exit code, elapsed time and timeout, and continues independent jobs after failures. It exposes `A38_HEAD_SHA` and `A38_BASE_SHA` to commands, removes GitHub token variables from job environments, and retains per-job logs locally. It terminates timed-out process groups. An interrupted run or checkout drift must never produce a successful report.
The runner identifies the GitHub repository from `origin` by default; for a fork, pass `--repository OWNER/NAME` with the PR target repository. Without `--private` or `--public`, visibility lookup requires `--github-session SESSION` bound explicitly in `$AGENT_HOME/github-accounts.json`. The executor verifies the selected account and refuses an absent binding or mismatched login; it never uses ambient host authentication. Explicit `--private` or `--public` supplies the report visibility without a GitHub lookup. A38 checks that visibility against the actual repository. The runner executes the complete job list sequentially, records each command's result, exit code, elapsed time and timeout, and continues independent jobs after failures. It exposes `A38_HEAD_SHA` and `A38_BASE_SHA` to commands, removes GitHub token variables from job environments, and retains per-job logs locally. It terminates timed-out process groups. An interrupted run or checkout drift must never produce a successful report.

Job adapter behavior is defined separately in [A38 job adapters](a38-job-adapters.md). Use `agent a38 job <commands|compose|http-smoke|immutable> --config '<JSON>'`; this standard intentionally does not duplicate adapter schemas.

Expand Down
128 changes: 128 additions & 0 deletions docs/ai-accounts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# AI accounts and roles

Static scripts that load this manifest select AI provider accounts and
user-defined roles from `$AGENT_HOME/ai-accounts.json`. Installation creates no
accounts, roles, or session selections. A missing file, `{}`, or null/empty
`accounts`, `roles`, and `sessions` leaves the configuration empty. There is no
implicit provider profile, model, or role from the host environment, hub
pairing, or built-in defaults.

This device-local manifest is used by `agent lane run`, the lane steps of
`agent run`, interactive Grok session starts, and optional Grok usage polling.
It does not implement the complete issue-to-PR coordinator or a sandbox.

The following is an **operator-supplied example**, never an installed default:

```json
{
"accounts": {
"provider-profile": {
"provider": "grok",
"config_dir": "/operator/path"
}
},
"roles": {
"my-builder": {
"account": "provider-profile",
"model": "operator-selected-model",
"access": "workspace-write"
}
},
"sessions": {
"chosen-session": {
"interactive": "my-builder",
"lanes": {
"grok:implementer": "my-builder"
}
}
}
}
```

Add as many named accounts, roles, and session bindings as needed. No fixed
account list, role list, or count is built in. Configurable role names are
chosen by the operator; they are distinct from the fixed workflow kinds
(`implementer`, `reviewer`, `pr-reviewer-quality`, `pr-reviewer-logic`) and from
the supported provider adapters (`grok`, `codex`). Those workflow kinds and
adapters are protocol capabilities used when resolving a lane slot, not
preinstalled user roles.

## Required fields

Each account requires:

- `provider`: `grok` or `codex`
- `config_dir`: absolute path to that profile's provider CLI configuration
directory (no NUL, newline, CR, or parent traversal)

Each role requires:

- `account`: name of a configured account
- `model`: explicit model id string (no default)
- `access`: `read-only` or `workspace-write` (no default)

The optional top-level `usage_session` selects an explicitly configured
interactive Grok session for automatic billing reads. Missing/null disables
those reads; it never chooses the host profile or the first available account.
The selected session must exist locally, be owned and active.

Each session may include:

- `interactive`: role name for the interactive runner, or omit/null when none
- `lanes`: map of slot → role name, or omit/null/`{}` when none

Lane slots are arbitrary non-empty single-line strings. Resolvers look up the
explicit key `vendor:workflow-kind` (for example `grok:implementer`) and require
the bound role's account provider to match `vendor`. For workflow kinds
`reviewer`, `pr-reviewer-quality`, and `pr-reviewer-logic`, the bound role must
use `access: read-only`; a writable binding is refused.

Unknown top-level, account, role, or session fields are rejected. Dangling
account or role references are rejected. Credentials and API tokens must not
appear in this manifest; they belong only inside each `config_dir`. Error text
from the loader does not echo credential contents.

## Process isolation prefix

`AIRole.env_prefix()` returns an `env` argv prefix for child processes. It
removes ambient `XAI_API_KEY`, `GROK_API_KEY`, `OPENAI_API_KEY`, `CODEX_API_KEY`,
`ANTHROPIC_API_KEY`, `CLAUDECODE`, `CLAUDE_CODE_ENTRYPOINT`, `GROK_HOME`, and
`CODEX_HOME`, then sets `GROK_HOME` or `CODEX_HOME` to the role's account
`config_dir`. It does not mutate the parent `os.environ`. Unrelated environment
variables are left for the child to inherit. This is process configuration
isolation, not a sandbox and not a claim that the provider CLI is already
authenticated for that profile.

## Interactive selection

`AIAccounts.for_session(session_id)` resolves `sessions[session_id].interactive`
and fails when that binding is absent or null. The loader may represent Codex
roles in the manifest. Interactive runtime support remains Grok-only initially;
unsupported interactive providers are refused. The configured model is required,
and a supplied `--model` must agree with it. A resumed conversation is pinned to
the configured role, account, model, access and configuration-directory identity;
a changed or missing binding requires a new session. Existing unbound Grok
conversation IDs are not silently adopted under a newly configured account.

## Migration from implicit defaults

Before this manifest, lane launchers and the interactive runtime used fixed
vendor/role lists and built-in model choices in code. After adopting
`ai-accounts.json`:

1. Create one account entry per provider CLI profile directory you intend to use.
2. Define roles with explicit `account`, `model`, and `access` (no omitted
fields).
3. Bind each session that should run lanes or an interactive runner: set
`lanes` keys such as `grok:implementer` and, when needed, `interactive`.
4. Existing sessions are unconfigured until those bindings are added. An empty
or missing file does not authorize a fallback identity.

Configure sessions explicitly before enabling launch paths after upgrading.
For example, the static script invokes `agent lane run --session chosen-session
--role implementer --vendor grok --spec-file task.md --no-tmux`; it resolves the
`grok:implementer` slot to the operator-defined role. `agent run` resolves slots
using its task session. Interactive starts use `agent session start --id
chosen-session --provider grok`. Raw terminal `--cmd` remains an explicitly
supplied script command, outside provider-profile launch enforcement; it is not
a sandboxed model interface. No model lane may invoke these execution commands.
17 changes: 10 additions & 7 deletions docs/github-accounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ Static scripts that load this manifest select GitHub accounts from
bindings. A missing file, `{}`, or null/empty `accounts` and `sessions` leaves
those covered GitHub executors unconfigured. There is no implicit account from
hub pairing, the host login, or environment tokens. CLI paths that never load
this file are outside this enforcement; see the remaining gaps below.
this file are outside this enforcement; see A38 visibility below for the
explicit `--github-session` path and the standalone PR guard's documented
workflow-token configuration.

The following is an operator-supplied example, not an installed default:

Expand Down Expand Up @@ -98,12 +100,13 @@ sessions explicitly before enabling these operations after upgrading.
Hub pairing and event ownership are separate: using a second GitHub execution
account does not re-pair the device or change ownership of its rows.

**Remaining gaps.** This manifest does not cover legacy ambient `gh` paths that
never load it. One reachable example is `agent a38` visibility lookup
(`gh repo view` when `--private` is omitted), which still uses the host `gh`
login. Configurable AI accounts and roles are part of the
[empty-default requirement](../DESIGN.md#198-configuration-starts-empty) and are
not implemented by this manifest.
**A38 visibility.** `agent a38 run` requires `--github-session SESSION` for
GitHub visibility lookup; the selected account is verified using this manifest.
Explicit `--private`/`--public` supplies report visibility without that lookup.
AI account and role selections use the separate [AI manifest](ai-accounts.md).
The standalone PR guard uses its documented explicitly supplied workflow-token
configuration; it does not select a host GitHub CLI login. Pure argv builders
and injected-runner libraries are not a sandbox; callers remain trusted scripts.

Transfer options are deliberately limited to the explicit allowlists in
`github_accounts.py`. Unknown options (including custom receive/upload programs),
Expand Down
Loading
Loading