Deploy an agent from GitHub
Install the B3OS Deploy app and each push deploys the repository's b3os.yaml. Or run b3os apply from a GitHub Actions workflow.
Version 1 of b3os.yaml is a draft and can change. The research-agent template below has been deployed only against a test double of the B3OS API; against beta-api.b3os.org only its dry run has run.
There are two ways in. The B3OS Deploy app deploys a repository's b3os.yaml on each push, with no workflow file and no key in the repository. Or a GitHub Actions workflow runs b3os apply with a project key, as the template below does.
With the B3OS Deploy app
Install the app
On GitHub, install B3OS Deploy on the account that owns the repository, for the repositories you choose. It reads their files and posts the plan; it cannot push. It asks to read contents and metadata and to write checks and pull requests, nothing else. In B3OS, only an owner or an admin of the organization can connect it.
Link the repository
Open Deploy from GitHub in the console and pick the repository. Then choose the branch, the b3os.yaml to deploy (its path from the repository's root) and the application's name, the name in the file. Linking deploys the branch as it is now.
Push
Each push to the branch deploys. B3OS reads the commit through the app, plans it and posts the plan as a check, then builds, starts the new generation and cuts over once its readiness probe passes. A plan with a problem deploys nothing. The application's Deployments tab in the console shows each step as it runs.
Open a pull request
A pull request gets the plan as a check and a comment. Nothing deploys.
B3OS renews the live deploy's services itself, so no schedule runs in the repository. Redeploy and roll back from the application in the console.
With a GitHub Actions workflow
The template is a whole repository for a research agent. Its harness, a small TypeScript service, runs in a sandbox on the B3OS node and calls the model served there, vision and a pack through the sandbox's grant, with no API key inside the sandbox. The Python the model writes runs in a second sandbox made for each question, which holds no credential and has no network (head and hands). A file in the repository, b3os.yaml, declares all of it. A GitHub Actions workflow runs b3os apply on every push to main, and b3os apply --keepalive on a schedule, which keeps the harness running.
The template is not yet published as a public repository. Its own README.md shows the plan and the deploy output, recorded against the test double.
What the agent does
You add a question to a table in your Postgres database. The harness claims it, and the agent reads pages with vision, runs a routine that reads several pages at once, lists a page's links with a program that ships in the repository, works things out in Python it writes, and answers with the node's model. When the question names a GitHub repository, the harness files the answer there as an issue through the GitHub pack.
In b3os.yaml | In the template |
|---|---|
| a model | b3os/default, reached through the OpenAI SDK at B3OS_API_URL plus /v1/infer with a placeholder key, as agents in sandboxes describes |
| a service | harness: built with npm ci from agent/package-lock.json, started as node src/main.ts, checked with GET /healthz on port 8080 |
| B3OS products | vision, and the routine gather-sources |
| a pack | io.b3os/github, with the stored connection labelled github-bot |
| a tool | extract-links, a program in agent/tools/ that runs inside the harness's sandbox |
| a sandbox shape | hands: a code-interpreter sandbox the harness creates for each question that runs code, with egress deny and without secrets or a grant, and deletes when the question ends |
| an external resource | research-db, your Postgres; its URL reaches the harness as the secret DATABASE_URL |
The harness's sandbox gets only the scopes these entries imply. Its egress allows the database's host and port and nothing else on the internet: the model, vision, the routine and the pack are reached through B3OS. The hands get no B3OS access and egress deny. A host that is not in the allowlist does not resolve either: with no hosts at all, nothing outside B3OS resolves, not even in DNS (egress with no hosts).
Before you start
-
A project key with
routines:read,routines:write,routines:run,sandboxes:read,sandboxes:write,sandboxes:run,vault:read,vault:run,actions:read,actions:run,infer:read,infer:runandvision:run. Give it a spend cap and an expiry (keys). -
A Postgres database the internet can reach.
-
Two connections in the same project. The repository never holds a credential; it names these by label:
bashprintf %s "$DATABASE_URL" | b3os connect new --type bearer --label research-dbb3os connect io.b3os/github --label github-botThe vault has no URL field, so the
postgres://URL is stored as a bearer connection's token. A connection with no hosts is never added to any request; it reaches the harness only as the sandbox secretb3os.yamlnames.
Deploy it
Copy the template
Make a repository of your own from the template. A public template repository is not published yet; once it is, choose Use this template on its GitHub page rather than forking it. GitHub runs no workflow in a new fork until you turn workflows on, and in a fork of a public repository it keeps scheduled workflows off, so the keepalive would not run. In b3os.yaml, set resources[0].hosts to your database's host and port, such as db.example.com:5432. Keep the port: b3os apply copies the entry into the harness's egress allowlist, and an entry without a port opens only ports 80 and 443. The harness can reach that host and port directly and nothing else.
Keep the repository public if you can. The keepalive runs as a scheduled GitHub Actions job, which is free in a public repository and billed in runner minutes in a private one (the workflow file's header has the arithmetic).
Add the secret
In the repository's settings, add a repository secret named B3OS_API_KEY holding the project key. Add it as a repository secret, not an environment secret: the keepalive job uses no environment, so it could not read one. It is the only secret the workflow reads.
Check that the workflow is on
Open the repository's Actions tab. If GitHub asks you to enable workflows, enable them. Then choose the b3os workflow and, if GitHub shows Enable workflow, choose it. A workflow that is off fails silently: nothing deploys, and a running harness stops within its timeout.
Push
Commit and push to main. The deploy job checks out the commit and runs b3os apply --yes.
Watch it deploy
The job prints the plan, then one line per step: the routine published, the dependencies installed with npm ci and snapshotted, a new generation of the harness started with the commit's tracked files of agent/, and its readiness probe passed. Then a summary. If any step fails before the new generation is ready, the deploy is undone and the previous generation keeps running.
Soon after, the same workflow shows its first scheduled keepalive run. GitHub can start scheduled runs some minutes late, but if none has appeared after 30 minutes, the schedule is off.
Open the console
Open Applications in the console and choose research-agent. The canvas shows the harness, its routine, the model, vision, sandboxes (the hands), the pack and the database. Ask a question with an INSERT INTO questions (question, repo) VALUES (...); the harness's calls appear in the request log.
Check the plan before you push
From a clone, with the key in B3OS_API_KEY:
bashb3os manifest validate # offline: the file, its schema and its referencesb3os apply --dry-run # reads the project; changes nothing
The dry run, like the deploy, uses what is committed: commit b3os.yaml and the routine file first. Its marks are those of the plan.
How the harness stays up
Each deploy starts a new generation: a sandbox restored from the build snapshot, given the source and the environment, and started. The build is reused until package.json or package-lock.json changes. A generation is a sandbox with a timeout of at most 3,600 seconds (sandbox limits), and every keepalive renews it. When the workflow stops running, the harness stops within that timeout.
When a new generation is ready, the old one gets SIGTERM. The template's harness then stops the agent, puts its question back in the queue, closes the database and exits. Its GET /healthz answers 200 only while its work loop is moving, and each keepalive runs that probe, so a harness whose loop is stuck gets a new generation.
To roll back, run the workflow by hand with ref set to an older commit. From a clone, b3os app rollback does the same without a checkout: it deploys the commit of the previous deploy that went live (or of --to dep_...), says in its plan and its deploy that it is a rollback, and leaves your working tree and HEAD as they are; a commit the clone lacks is an error that names the fetch to run. Keepalive recreates a lost harness from the commit it ran, never from the newest one on main, so it does not undo a rollback, and it says so: running caebec0 by rollback; HEAD is ee70e90. The next b3os apply deploys HEAD again.
What the template leaves out
- An address. The harness takes its work from the database; it gets no stable URL in this design. A service you give a public port is served at its preview URL under a path prefix (
/sbx/.../), so absolute asset paths 404 and cookies are not kept; the plan says so in one line under the service, with a link to ports. - Previews. Pull requests do not deploy.
- More than one copy. One generation serves at a time, apart from the overlap during a cutover.