Skip to content
Draft
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Trajectory: Publish fleet and attach subpaths and forward sandbox readonlyPaths

> **Status:** ❌ Abandoned
> **Started:** September 18, 2026 at 03:11 PM
> **Completed:** September 18, 2026 at 03:21 PM

---

## Key Decisions

### Implement shared attach transport in Cloud with SDK re-exports; preserve ESM exports and inferred completion semantics
- **Chose:** Implement shared attach transport in Cloud with SDK re-exports; preserve ESM exports and inferred completion semantics
- **Reasoning:** Reviewed plan identifies Cloud as the consumer import target, no remote exit-code protocol, and no server mount handler in this repository. D4 running-agent orchestration remains pending user scope clarification.

---

## Chapters

### 1. Work
*Agent: default*

- Implement shared attach transport in Cloud with SDK re-exports; preserve ESM exports and inferred completion semantics: Implement shared attach transport in Cloud with SDK re-exports; preserve ESM exports and inferred completion semantics
- Abandoned: Attach extraction and readonlyPaths client implementation ready; full spawnFleetSandbox orchestration awaits reviewed-plan.md D4 scope decision. Server chmod enforcement is outside this repository.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"id": "traj_qdtkdvki0xoh",
"version": 1,
"task": {
"title": "Publish fleet and attach subpaths and forward sandbox readonlyPaths"
},
"status": "abandoned",
"startedAt": "2026-09-18T15:11:05.520Z",
"completedAt": "2026-09-18T15:21:12.959Z",
"agents": [
{
"name": "default",
"role": "lead",
"joinedAt": "2026-09-18T15:20:29.731Z"
}
],
"chapters": [
{
"id": "chap_jnv5kvm9t42d",
"title": "Work",
"agentName": "default",
"startedAt": "2026-09-18T15:20:29.731Z",
"endedAt": "2026-09-18T15:21:12.959Z",
"events": [
{
"ts": 1789744829731,
"type": "decision",
"content": "Implement shared attach transport in Cloud with SDK re-exports; preserve ESM exports and inferred completion semantics: Implement shared attach transport in Cloud with SDK re-exports; preserve ESM exports and inferred completion semantics",
"raw": {
"question": "Implement shared attach transport in Cloud with SDK re-exports; preserve ESM exports and inferred completion semantics",
"chosen": "Implement shared attach transport in Cloud with SDK re-exports; preserve ESM exports and inferred completion semantics",
"alternatives": [],
"reasoning": "Reviewed plan identifies Cloud as the consumer import target, no remote exit-code protocol, and no server mount handler in this repository. D4 running-agent orchestration remains pending user scope clarification."
},
"significance": "high"
},
{
"ts": 1789744872960,
"type": "note",
"content": "Abandoned: Attach extraction and readonlyPaths client implementation ready; full spawnFleetSandbox orchestration awaits reviewed-plan.md D4 scope decision. Server chmod enforcement is outside this repository.",
"significance": "high"
}
]
}
],
"commits": [],
"filesChanged": [],
"projectId": "AgentWorkforce/relay",
"tags": [],
"_trace": {
"startRef": "c97830275c0849f8ae1ed7fc1f347a5198124b11",
"endRef": "c97830275c0849f8ae1ed7fc1f347a5198124b11"
}
}
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ All notable changes to Agent Relay will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [Unreleased - Minor]

### Added

- `@agent-relay/cloud/attach` and `@agent-relay/sdk/attach` expose fleet terminal attachment with a private local stdio socket and completion promise.
- `@agent-relay/cloud/fleet` and `@agent-relay/sdk/fleet` expose existing sandbox ensure and deletion primitives.
- Fleet sandbox ensure and `fleet spawn --sandbox-readonly-path` forward explicit read-only Relayfile subtree requests to Cloud for server-side enforcement.

## [12.2.4] - 2026-09-18

Expand Down
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<p align="center"><img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-3178C6?style=flat-square&logo=typescript&logoColor=white"> <a href="https://github.com/AgentWorkforce/relay/actions/workflows/test.yml"><img alt="Tests" src="https://img.shields.io/github/actions/workflow/status/AgentWorkforce/relay/test.yml?branch=main&label=tests&style=flat-square"></a> <a href="https://github.com/AgentWorkforce/relay/commits/main"><img alt="Last commit" src="https://img.shields.io/github/last-commit/AgentWorkforce/relay/main?label=last%20commit&style=flat-square"></a> <a href="https://www.npmjs.com/package/@agent-relay/sdk"><img alt="npm version" src="https://img.shields.io/npm/v/@agent-relay/sdk?label=npm&style=flat-square"></a> <a href="https://www.npmjs.com/package/@agent-relay/sdk"><img alt="Downloads" src="https://img.shields.io/npm/dm/@agent-relay/sdk?label=downloads&style=flat-square"></a> <a href="./LICENSE"><img alt="License" src="https://img.shields.io/badge/license-Apache%202.0-black?style=flat-square"></a></p>

# Infrastructure for coding agents

Tired of copy/pasting from Claude Code into Slack so your coworker can paste it into their agent?

Ever put an important rule in a skill or AGENTS.md, only for the agent to completely ignore it?
Expand All @@ -13,34 +14,40 @@ Agent Relay is an open-source toolkit for problems like these. It gives engineer
Use the pieces you need, or combine them to build workflows across agents, tools, people, and machines.

### Messaging

Claude/Codex/etc can talk directly through shared channels, threads, DMs, files, search, and real-time events. Agents can run on different machines and still coordinate in the same workspace.

[Read the docs](https://agentrelay.com/docs/introduction)

### Integrations

GitHub, Linear, Notion, Slack, and other tools are exposed as a virtual filesystem. Agents use ls, cat, grep, and ordinary file writes to work with them.

[Peep the open source repo](https://github.com/agentworkforce/relayfile)

### Shared Sessions

Capture coding agent sessions so your team and their agents can search previous work, decisions, and context.

[How we capture sessions](https://github.com/agentworkforce/relayhistory) <br>
[How we capture decisions](https://github.com/agentworkforce/trajectories)

### Flows
Turn instructions you hope an agent follows into workflows you can enforce.

Turn instructions you hope an agent follows into workflows you can enforce.

Define multi-step workflows in TypeScript with deterministic checks, required steps, and human gates. Put the rules that matter in code instead of relying on a skill or prompt to be remembered and followed.

[Learn how write a flow](https://github.com/agentworkforce/flows) (or lets be honest, show your agent how)

## Getting Started
The easiest way to get started is to use [Agent Relay Cloud](https://agentrelay.com/flows).

The easiest way to get started is to use [Agent Relay Cloud](https://agentrelay.com/flows).

You don't need a credit card and you can explore all the pieces without setting up any infrastructure.

### Self Hosting

Agent Relay has self hosting options for each primitive. We're happy to help you set up the whole system on your environment, just reach out to our team hi(at)agentrelay.com and we'll walk you through it.

## License
Expand Down
9 changes: 6 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,19 @@ agent-relay fleet spawn claude \
--task 'Review the live draft under /workspace/live-review/run-123'
```

Use `--sandbox-readonly-path '/reference/**'` to request a read-only Relayfile
subtree. It requires `--sandbox` with Relayfile enabled and accepts explicit
`/path/**` subtrees (no traversal or other wildcards). This client forwards the
request; the deployed Cloud ensure handler must implement chmod enforcement.

The ESM `@agent-relay/cloud/attach` and `@agent-relay/sdk/attach` entries expose
`startFleetNodeAttachProxy({ nodeId, mode })`. An omitted agent is discovered
only when the node has exactly one agent. `socketPath` accepts one raw stdio
connection; `close()` removes it. `finished` reports an inferred status (0 for
terminal closure or detach, 1 for transport failure), because Relaycast does
not currently transmit the remote harness exit code. Existing CLI broker
transport fields remain available for compatibility.

`--session-ref` is a real CLI resume, not a logical collaboration label. Pass
the actual Claude session ID or Codex thread ID and target its origin node.
`--cwd` must name an absolute directory that exists on the selected node. The
Expand Down
38 changes: 38 additions & 0 deletions packages/cli/src/cli/commands/fleet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,8 @@ describe('fleet command support', () => {
REPLAY_SANDBOX_NAME,
'--sandbox-relayfile-path',
'/live-review/run-123/**',
'--sandbox-readonly-path',
'/live-review/run-123/reference/**',
'--name',
'sandbox-worker',
'--task',
Expand All @@ -999,6 +1001,7 @@ describe('fleet command support', () => {
maxAgents: 1,
mountRelayfile: true,
relayfilePaths: ['/live-review/run-123/**'],
readonlyPaths: ['/live-review/run-123/reference/**'],
sandboxId: REPLAY_SANDBOX_ID,
forceProvision: true,
providerId: 'agent37',
Expand Down Expand Up @@ -3962,3 +3965,38 @@ describe('fleet command support', () => {
expect(errors.join('\n')).toMatch(/relay cloud enroll/);
});
});

describe('sandbox read-only path guards', () => {
it.each([[], ['--sandbox', '--no-sandbox-relayfile']])(
'rejects unavailable mounts (%j)',
async (...flags) => {
const ensureCloudFleetSandbox = vi.fn();
const error = vi.fn();
const program = new Command();
program.exitOverride();
registerFleetCommands(program, {
ensureCloudFleetSandbox,
sdk: { error, exit: vi.fn() as never },
});
await program.parseAsync(
[
'fleet',
'spawn',
'claude',
...flags,
'--sandbox-readonly-path',
'/reference/**',
'--name',
'worker',
'--task',
'review',
],
{ from: 'user' }
);
expect(error).toHaveBeenCalledWith(
expect.stringContaining('--sandbox-readonly-path requires --sandbox')
);
expect(ensureCloudFleetSandbox).not.toHaveBeenCalled();
}
);
});
13 changes: 12 additions & 1 deletion packages/cli/src/cli/commands/fleet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { findProjectRoot } from '@agent-relay/config';
import {
CloudFleetSandboxProvisionError,
deleteCloudFleetSandbox,
ensureCloudFleetSandbox,
materializeCloudRelayfileRepository,
resolveWorkspaceByKey,
type CloudFleetSandboxProviderId,
type CloudRelayfileRepositoryMaterialization,
type EnsureCloudFleetSandboxResult,
} from '@agent-relay/cloud';
import { ensureCloudFleetSandbox } from '@agent-relay/sdk/fleet';
import { HarnessDriverClient } from '@agent-relay/harness-driver';
import {
createWorkspaceClient,
Expand Down Expand Up @@ -331,6 +331,10 @@ export function registerFleetCommands(
'--sandbox-relayfile-path <path...>',
'Mount only these Relayfile subtrees (each path must end in /**)'
)
.option(
'--sandbox-readonly-path <path...>',
'Read-only Relayfile subtrees (/path/**); requires Cloud enforcement'
)
.option('--no-sandbox-relayfile', 'Provision the sandbox without mounting Relayfile')
.option('--channel <name>', 'Channel for the worker to join')
.option('--persona <persona>', 'Worker persona (automatic placement)')
Expand Down Expand Up @@ -397,6 +401,12 @@ export function registerFleetCommands(
throw new Error('--sandbox-provider must be daytona, e2b, or agent37.');
}
const mountSandboxRelayfile = options.sandboxRelayfile !== false;
const sandboxReadonlyPaths = optionalTextList(options.sandboxReadonlyPath, 'Sandbox read-only path');
if (sandboxReadonlyPaths && (!useSandbox || !mountSandboxRelayfile)) {
throw new Error(
'--sandbox-readonly-path requires --sandbox and cannot be combined with --no-sandbox-relayfile.'
);
}
const sandboxRelayfilePaths = optionalTextList(options.sandboxRelayfilePath, 'Sandbox Relayfile path');
if (useSandbox && targetNode) {
throw new Error('--sandbox cannot be combined with --node or --target-node.');
Expand Down Expand Up @@ -591,6 +601,7 @@ export function registerFleetCommands(
requiredCapability: `spawn:${cli}`,
maxAgents: 1,
mountRelayfile: mountSandboxRelayfile,
...(sandboxReadonlyPaths === undefined ? {} : { readonlyPaths: sandboxReadonlyPaths }),
...(liveRepository
? { relayfilePaths: liveRelayfileMountPaths(liveRepository, sandboxRelayfilePaths) }
: sandboxRelayfilePaths === undefined
Expand Down
Loading