0.3.0
Install: npm install @ambionframework/ambion@0.3.0
On npmjs:
@ambionframework/ambion@ambionframework/journal@ambionframework/assistant@ambionframework/pi@ambionframework/claude@ambionframework/codex@ambionframework/cloudflare@ambionframework/workspace@ambionframework/just-bash@ambionframework/workstation@ambionframework/simulator
Retired and deprecated: @ambionframework/git. Use @ambionframework/just-bash/git.
Live evidence: the live run on the tagged commit passes the Pi and Claude jobs. Two cases failed: restart.test.ts on the Codex job ("The activation ran past its lease."), and the assistant eval "keeps a constraint of the first exchange in the second" in the package job. The full live tier also ran on the owner's machine on 1e2071d, one commit before the tag. Both of those cases passed there, and so did every other case except the workbench tool-set case that #343 fixes.
The work of a seat outlives its activation. A shell command runs as a
background process, and an agent comes back to its work with a scheduled
say. A workstation keeps git repositories for its agents, and the
simulator runs evals on a room. Every library package needs Node 22.19 or
newer.
Packages
| Package | What it gives |
|---|---|
@ambionframework/ambion |
The kernel: room, journal vocabulary, rules, and hosting |
@ambionframework/journal |
The append-only journal |
@ambionframework/assistant |
The default assistant |
@ambionframework/pi |
The Pi executor, and runAgent for one agent outside a room |
@ambionframework/claude |
The Claude Agent SDK executor |
@ambionframework/codex |
The Codex SDK executor |
@ambionframework/cloudflare |
A room and its seats as Durable Objects |
@ambionframework/workspace |
The workspace interface, its tools, a SQLite backend, and the git helpers in ./git |
@ambionframework/just-bash |
A shell and a filesystem in the process, and justGitBackend in ./git |
@ambionframework/workstation |
A shell over SSH on one server, one Unix account per agent, and workstationGitBackend |
@ambionframework/simulator (new) |
Evals: an actor plays a person in a room, and a judge grades the run |
@ambionframework/git (retired) |
Use @ambionframework/just-bash/git |
New
A shell command runs in the background. bash starts every command as
a background process and returns a handle. A process outlives the call and
the activation that started it. The files of the bash backend hold the
process table, so a new run of the host reads the same table. No message
wakes a seat when a process ends: the agent waits for the result inside
the activation, and the guidance says so. A host that wants a wake posts a
message. See Processes.
import { defineHuman } from '@ambionframework/ambion';
const lab = defineHuman({
name: 'lab',
identity: 'The lab host. It reports each process that ends.',
});
const visit = await room.visit(lab);
workspace.processes.subscribe((event) => {
const { handle, name, agent, state, room: started } = event.process;
if (event.type !== 'ended' || started !== room.name) return;
visit
.send({
to: agent,
text: `Process ${name ?? handle} is ${state}. Call status with ${handle} for its output.`,
key: `process-ended:${handle}`,
})
.catch((error: unknown) => log.error(error));
});ps,status,wait, andcanceljoinbash.pslists the
running processes of the caller. The handle tools take a handle of the
caller.bashtakes an optionalname, a label thatpsand the
reminder show. Each process is a directory,
~/.processes/<handle>/, that holds the spec, the whole output in
out, the process id, and the end.- A result gives the new output.
bash,status,wait, and
cancelgive the output after a cursor that the process keeps in
~/.processes/<handle>/cursor, and move it.details.readholds the
byte range. A poll of a long build gives each part once. Each read goes
through the shell capture, which removes escape sequences and carriage
returns, as Pi'sbashtool does. waittakeshandles. It returns when the first of up to 16
processes ends, with the new output of each process that ended and the
state of each one that still runs.- A wait ends before the activation does. The room puts
deadlineon
each view, andToolContext.deadlinecarries it to each tool call: when
the room ends the activation, in milliseconds on the wall clock.bash
andwaitstop their wait 30 seconds before it, and the result says so. - A new run of the host adopts the live processes of an earlier run.
The table re-arms the timeout of each one, andcancelstops it through
its process id. A process that ended with the earlier run, with no exit
file, isfailedwith the message "The host run ended before the
process did." Workspace.processesis the host's view.list,subscribe, and
cancelreach the processes of the agents that used the workspace in
this run.listreturns a promise. The root entry of
@ambionframework/workspaceexportsProcessEvent,ProcessKind,
ProcessQuery,ProcessState,ProcessStatus, and
WorkspaceProcesses.- A tool bundle can remind a seat.
ToolBundle.remindgives text, or
a promise of text, for each respond activation, and
AgentExecutor.remindersholds the reminders of the bundles. The
executor resolves them once for each activation, with a bound of 5
seconds for each, and aborts the signal of a reminder at the bound.
renderActivationtakes the resolved text as its third argument and
adds it before the ask line. The main entry exportsReminderand
ReminderSeat. The hosting entry exportsresolveRemindersand
REMINDER_TIMEOUT_MS. The Pi executor sends a continued session the
reminders before the delta. The workspace reminds each seat of its
processes. - The workstation keeps a session open while any environment is open
over it. A process holds an environment for its whole run. - The workbench shows the background processes with
/ps. A side
panel lists the processes of the agents, shows the end of the chosen
output, and cancels a running process on a secondx.
An agent comes back to its work later. An agent says to itself with
after, in seconds. The exchange closes while the say waits. When the say
is due, the room writes a returned say, which wakes the agent and opens an
exchange for the owner of the first one. See
Exchange.
saytakesafter. A say to oneself withafterschedules it. The
room stampsowner, the owner of the open exchange, on the said entry,
and refusesafterin any other say. The result names the due time and
the seq of the say as its handle.- The
returnedentry. The room writes{ to, message, owner, text, refs }when a scheduled say is due. It has nofrom. It wakes one
seat, the one thattonames, and steers no other. It opens an exchange
forownerwhen none is open.isReturnedandReturnedMessageare
new exports. limits.scheduleboundsafterfromminAftertomaxAfter
seconds, 60 to 604,800 by default, and the says of one seat that wait,
pending, 4 by default.- The agent sees its pending says.
CollaborationContext.scheduled
carries the pending says of the seat in each response activation, and
the render lists them.renderPendingin/hostinggives that list for
a seat that continues its session. - A seat or the host dismisses a pending say. The
dismisstool takes
the handle of a pending say of the seat, and the room writes a
dismissedentry{ from, message }. The room does not return the say.
room.dismiss(handle)dismisses any pending say, with nofrom, and
returns whether it wrote the entry.room.scheduled()lists the pending
says. The Cloudflare room object serves them asdismissand
scheduledSays, because Workers keep the namescheduled.
DismissedMessageis a new export, and/hostingexportsDISMISS. RoomRead.scheduledlists the says that wait to return, each a
PendingSaywith its due time.PendingSayis a new export.- The workbench shows a returned say, and notes each say that waits.
Each note names the handle of the say./dismiss <n>dismisses the say,
and the palette lists the says that wait. A dismissed say reads
dismissedin place of its return time.
A workstation keeps the git repositories of its workspace. One
account on the server, such as lab-git, owns every repository. Each
agent clones and pushes with its own git over SSH, with a key that works
only from the server and only until keyTtl. The host opens no port. See
Workstation git.
workstationGitBackendprepares the account, writes the forced
command~/.ambion/serve, registers each template by a rename, and runs
list,get, andforkas scripts on the server. A fork lands with
one rename.identityForissues an Ed25519 key for each agent and
writes its line to~/.ssh/authorized_keys.ambionunderflock, with
restrict,from,expiry-time, andcommand.
@ambionframework/workstationexportsworkstationGitBackend,
WorkstationGitOptions,WorkstationGitAccess, and
WorkstationGitIdentity.workstationBackendcarries the git transportssh. Its
gitTransportsis['ssh'], so it pairs withworkstationGitBackend.
At eachconnect, it writes the agent's key, aknown_hostsfile, and
an ssh configuration for the alias into~/.sshwith mode0600. It
makesInclude ambion-git.confthe first line of~/.ssh/config, and
it keeps the other lines.
@ambionframework/simulator runs evals on a room. simulate(room, options) drives a room that the test started. An actor plays a person,
one exchange at a time, and the loop waits for the close and the summary
under one deadline, exchangeMs. The run holds the moves, each exchange
with its closed view, one read of the room, the events, and the usage. It
ends with stopped, limit, timeout, or failed. See
Simulator.
scriptedActorplays a fixed list of moves.agentActorandagentJudgerun the person and the grade on a
model. Each takesmodel,tools,bundles,services, and
timeoutMs, and runs onrunAgent. The actor ends each move with
sendorstop, and the tools see the person inctx.agent. The judge
reads the record between two lines that carry a random token, and ends
withgrade: one finding for each criterion, in the order of the list,
reason first. The judge attaches each criterion, andgraderefuses a
list of the wrong length.runAgentruns one Pi agent outside a room. It takes a model, a
routing name, the agent that the tools see, a system prompt, one prompt,
tools and bundles, and the names of the tools that end the run. It runs
Pi'sAgentHarnessuntil the agent calls one of them, and returns that
call, the calls before it, and the usage of every request. Asignal
aborts the run.@ambionframework/piexportsrunAgent,
RunAgentRequest,RunAgentResult, andRunAgentCall.- A Pi seat takes a thinking level.
pi({ thinking })takes a Pi
ThinkingLevel, and the harness sends it to the provider. Absent, the
level isoff, as before.runAgent,defineAssistant,agentActor,
andagentJudgetakethinkingtoo. - The assistant's live suite runs on the simulator. It passes on
anthropic/claude-sonnet-5andopenai/gpt-5.6-lunaatmedium, and
each model grades the other.
Fixes
- A spent usage limit, a billing refusal, or a spent quota fails in one
attempt. The Pi, Claude, and Codex executors readusage limitand
billing_erroras permanent. Pi also readsinsufficient_quotaand
exceeded your current quota. OpenAI sends a spent quota with a 429, so
before this change a Pi seat on OpenAI retried it to the cap. A rate limit
stays transient. - A Pi seat with a model the registry does not hold fails in one
attempt.Unknown model, and the harness codesmodel_unavailableand
configured_tools_unavailable, are permanent. A retry reads the same
configuration. Before this change, the room retried them to the cap. - A failed activation names the failure in the provider's words. A
provider error that arrives as a status and a JSON body, as in400 {"type":"error",...}, now reads400 invalid_request_error: <message> (request <id>). The Pi, Claude, and Codex executors give this text to the
trace, theerrorevent, and the pass result.providerMessagein
@ambionframework/ambion/hostingmakes the text for another executor. - The Workbench shows why a closed exchange has no reply. When the room
gave up on a reply, the line under the exchange names the seat, whether
the room retried, and the reason from the trace./stepsopens the
attempt that ran, and not the attempt the room abandoned after it. directoryBackendruns each filesystem change as trusted code of
just-bash. just-bash 3.4.2 starts a queued change in the async context
of the change before it. When a script made that earlier change and then
ended, the defense layer of just-bash blocked the queued change. Each
later change on the directory then waited with no end, and so did the
workspace owner,wait, and the host's list of processes.
Breaking changes
There is no compatibility promise before 1.0.0. Some journal bodies
changed. A 0.3.0 runtime reads a 0.2.0 journal, and a 0.2.0 runtime must
not read a 0.3.0 journal.
- The journal changes. A said entry takes
afterandowner, and the
returnedanddismissedentries are new. A returned say opens an
exchange, so the verified ruleopensExchangeaccepts it. Messagehas two more members,ReturnedMessageand
DismissedMessage. Code that switches onkindmeetsreturnedand
dismissed.Roomhasdismissandscheduled, andRoomReadhas
scheduled. A value that implementsRoomor builds a read by hand
adds them.- A respond activation has the
dismisstool, andsayhas anafter
parameter. A tool namedismissof an agent gets a refusal, and a
tool list or schema that a test pins lists both. bashreturns a handle, and waits up towaitseconds, 10 by
default. A command that runs longer keeps running, and the result
says so. A process can run fortimeoutseconds, 600 by default. Before,
a command held the bash owner and stopped after 30 seconds by default.- Every workspace has eight tools before the tools of its other
backends. The tool line of the guidance counts them. dispose()stops every running process of this run before the bash
backend releases its handles.- The default assistant is passive at
broadcast, and keeps to
membership and summaries. It sends nothing to a specialist at
broadcastorpresenceattention. It sends no correction, no relay,
and no question to the person during the exchange. The summary reports
a superseded fact, a broken constraint, and a question for the person.
The assistant answers a person or a specialist that addresses it, and it
sends one directed request to an idle specialist atnamedattention. A
constraint stays in force until the person withdraws it. Its identity
now reads "Room assistant. Seats and unseats specialists as the request
needs, and summarizes each exchange." See
Default assistant. @ambionframework/gitis gone. Its git backend moves into the new
entry@ambionframework/just-bash/git, and the template helpers move
into the new entry@ambionframework/workspace/git. The root entry of
@ambionframework/just-bashloads nonode:sqlite.justGitBackendhas nohandlerand nourloption. Every clone
URL starts withhttp://git.ambion.invalid, and the backend serves the
process it runs in.GitAccessholdstransportalone.prefix,fetch, and
credentialFormove toJustGitAccess, andcredentialsForgoes.
JustGitBackend.accessis aJustGitAccess, whosetransportis
in-processand whosefetchis always set.- A bash backend lists the git transports it carries in
BashBackend.gitTransports.openWorkspacethrows when the bash
backend does not carry thetransportof the git backend. The error
names that transport, theserverof the git backend, and the
transports of the bash backend. A bash backend with nogitTransports
carries none.memoryBackendanddirectoryBackendcarry
in-process, and they refuse an access of another transport at
connect. - The workstation writes no
~/.git-credentials. Its agents reach
git throughworkstationGitBackendand thesshtransport. - A registration with a changed source updates its template. Before,
it failed with an error that named the template, and the host
registered the change under a new name. Now both git backends
fast-forwardtemplates/<name>to a new commit whose parent is the old
tip. A changed description replaces the old one. A fork keeps the
commit it came from.justGitBackendcommits the change to
template-sources/<name>and moves the template's ref.Registrygets
describe. gitConformanceasks the harness for each credential fact.
GitConformanceBackendgets four hooks:sourcesCredential,
issueCredentials,writeCredential, andprobeCredential. Each hook
takes the pair that the case opened, aGitConformancePair, and
probeCredentialgives aGitConformanceProbe. The conformance entry
exports both types.GitConformanceBackend,GitConformanceStore, and
gitConformancetake the type of the git backend as a parameter.
GitConformanceOptions.tokenTtlis nowcredentialTtl, and
GitConformanceBackend.shortestTokenTtlis nowshortestCredentialTtl.
Removed and moved names, by entry:
| Entry | Change |
|---|---|
@ambionframework/git |
Moved to @ambionframework/just-bash/git: sqliteGitStorage, JustGitBackend, GitStorage, OpenGitStorage, Registry, RegistryRow. Renamed there: gitBackend is justGitBackend, and GitBackendOptions is JustGitBackendOptions |
@ambionframework/git |
Moved to @ambionframework/workspace/git: fromDirectory, TemplateFiles, TemplateRegistration, TemplateSource |
@ambionframework/git |
Gone: PACKAGE_NAME |
@ambionframework/workspace |
Moved to @ambionframework/just-bash/git: GitFetch, GitCredential |
New entries: @ambionframework/just-bash/git and
@ambionframework/workspace/git. The second also exports filesOf,
hashesOf, sameFiles, changeTo, validName, namespaceOf,
assertAgent, readOnly, TEMPLATES, and SOURCES.
Stored formats that changed: a said entry takes after and owner,
and the returned and dismissed entries are new. The journal format
stays 1. A process of a workspace keeps its files in
~/.processes/<handle>/.