D-301 Team
Team plan
One policy on every developer's machine. One log of what agents were refused. A person approving more access, from one place.
Set up a team
On one machine, boundlane server is the console. It listens on localhost.
boundlane serverThat listens on http://127.0.0.1:8787 and nowhere else. The database holds two users, dana@acme.dev (admin) and li@acme.dev, and the signing key. The first start publishes developer-default when the prover accepts it.
Create the team in the console. You become its first admin. Locally, Dana already is.
Publish a policy. Start from
developer-defaultand add the hosts your projects need. See Publish a policy. Locally:boundlane policy publish acme.yaml, signed in as Dana.Invite developers. Each one installs the CLI and signs in.
boundlane loginopen http://127.0.0.1:8787/device
code KQXT-MRWD
signed in dana@acme.dev, team acme
machine dana-mbp, enrolled
policy acme r1, verified and cachedFrom then on, boundlane run on that machine uses the team's policy. The project file is not used to widen it. See Enroll machines.
The local server also has sam@acme.dev, a member, so three accounts can sign in. Open http://127.0.0.1:8787/console on this machine. Dana publishes there. A host change says it applies to running agents. boundlane sync loads that change. A path change says the next run creates a new sandbox.
boundlane forward sends denies and requests to that console. Dana approves or denies there. The next forward pass makes the same call the gateway already uses, and the agent retries against the new rule. If the gateway says the request changed after the review, that review is not sent again. The request goes back to pending, or a replacement appears, and a person reviews it. Stop the server and boundlane status still shows the last signed revision. A sandbox that already started keeps enforcing the policy it was given.
Publish a policy
Edit the policy in the console. On publish, the control plane compiles it for every agent the policy names, runs the same prover check as the CLI, and refuses to publish anything that is not within_boundary. Each published version gets a revision number and is signed. The signed bundle is the policy document and that revision.
A machine checks the signature before it uses a bundle, and it ignores a bundle that fails or that is older than the revision it already has. Before a sandbox starts, the CLI compiles that document for the agent and runs the prover again. A check that fails means the sandbox does not start. The details are in Publish and revisions.
| You changed | Running sandboxes | The console says |
|---|---|---|
| Hosts | Updated live, on the CLI's next check. | "Applies to running agents." |
| Paths or workspace access | Keep running on the old revision. The next run creates a new sandbox. | "Takes effect on the next run. Running agents keep the old paths." |
Machines
Each enrolled machine reports the OpenShell version, the sandbox driver, the policy revision it last loaded, and when it last checked in. Machines call us. We never call them.
Decisions
The decision log shows every allow and deny from every enrolled machine. Filter by machine, sandbox, destination, or action. Records are kept for 90 days by default.
time machine sandbox action destination process
10:42:07 dana-mbp bl-web-4f2a deny paste.example.net:443 curl
10:42:31 dana-mbp bl-web-4f2a allow GET pypi.org/simple/... python3.12
10:44:02 li-x1 bl-api-90cc deny POST api.github.com/... ghA gap in that log means the machine lost part of the stream. The usual cause is a gateway restart, or a buffer that dropped decisions before the machine could send them. The row names the sandbox and the span. Those decisions are not recovered from another file.
Approvals work from the console the same way they work in the terminal. See Approving on Team.
What our cloud receives
One record per decision line on the gateway's stream, with these fields and nothing else:
| Field | Example |
|---|---|
| Time | 2026-10-03T10:42:07Z |
| Sandbox and machine | bl-web-4f2a, dana-mbp |
| Policy revision | r14 |
| Kind of event | Network activity or HTTP activity |
| Action | Allowed or denied |
| Destination | Host and port, or method and path with the query string removed |
| Process | curl |
| Rule | The name of the rule that matched, if any |
| Reason | The sandbox's reason for a deny. Empty on an allow. |
A gap is a separate record. It names the sandbox, the time of the last decision we have, and the time the stream resumed. It carries no destination and no action.
We never receive your source code, file contents, request bodies or headers, terminal output, the agent's conversation, model keys, or GitHub tokens.
Drift
A developer owns their laptop. They can run OpenShell directly or approve a request on the machine. Team cannot stop that, but it records it. A machine is flagged when a sandbox runs a policy that does not match the published revision, or when the sandbox records an approval that did not come from the console. See Drift.
If you need enforcement the machine's owner cannot change, run the gateway where developers do not administer it. That is the License plan, on your cluster. Team and License are on the waitlist until there is a public price.
When our cloud is unreachable
- Sandboxes keep enforcing the last policy they loaded.
- The CLI keeps using the last signed policy it verified.
- Decision records wait on the machine and upload later. Decisions the gateway still has are sent once. Decisions it has already dropped become a gap in the console. If the local queue fills, the CLI says how many records were dropped.
- Requests stay pending. The blocked call stays blocked.
- A machine that has never received a policy refuses to start a sandbox.
Every failure case is in When something is down.
Not in Team
The License plan adds single sign-on, a SIEM export, and the control plane in your VPC. A JSONL export of the same decision records is what you point your own tools at.