Skip to content

Commit 7210558

Browse files
khaliqgantclaude
andauthored
feat: add API conformance tooling and @relayfile/core package (#11)
* feat: add API conformance suite for cross-server parity Adds scripts/conformance.ts — a 23-test suite that verifies any relayfile-compatible server correctly implements the API contract. Both the Go server and the Cloudflare Workers server must pass this. Runnable against any server URL via RELAYFILE_BASE_URL env var. Covers: file CRUD, If-Match wildcard, conflict detection, cross-agent metadata visibility, semantic queries (property/relation/comment), ACL permission enforcement, WebSocket catch-up, writeback lifecycle, bulk ops, export, concurrent multi-agent writes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add relayfile-workspace skill for multi-agent collaboration Adds a skill that teaches agents how to work in a shared relayfile virtual filesystem — covering metadata semantics, conflict handling, discovery queries, ACL permissions, and collaboration patterns. Designed for agents on platforms like Daytona where multiple agents share the same workspace concurrently. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: implement @relayfile/core with all business logic modules * refactor: rename relayfile core package directory * refactor: rename relayfile cli and sdk package directories * fix: address 3 review finding(s) conformance.ts: correlation IDs now meet minLength:8 API spec requirement writeback.ts: remove status reset to pending after successful send (infinite loop) query.ts: fix spurious nextCursor when filters eliminate rows without hitting limit Co-Authored-By: My Senior Dev <dev@myseniordev.com> * workflow fixes * fix: address 37 review finding(s) Security fixes: - webhooks.ts: ACL enforcement hook, signature verification callback, strip permissions from webhook-provided semantics, pagination guard - files.ts: path traversal prevention via .. resolution in normalizePath - files.ts: conflict response no longer leaks file content preview - acl.ts: document default-open security model Reliability fixes: - semantics.ts: mergeSemantics now actually merges (was discarding existing) - semantics.ts: size limits on arrays (MAX_ARRAY_ENTRIES=100) - writeback.ts: correlationId parameter now used (was voided) - writeback.ts: getPendingWritebacks filters by status=pending - writeback.ts: dispatchWriteback sets status to dispatched after send - export.ts: null guard on Response.body (was non-null assertion) - storage.ts: document concurrency contract for StorageAdapter Code quality: - utils.ts: extract normalizePath with .. resolution (was duplicated 6x) - files.ts: deduplicate normalizeSemantics (import from semantics.ts) Testing: - conformance.ts: health check captures and reports errors (was empty catch) - conformance.ts: writeback test asserts items exist (was silently skipping) - conformance.ts: typed interfaces replace pervasive any casts - conformance.ts: ACL gap now tracked as test failure - conformance.ts: JWT query string security concern documented Co-Authored-By: My Senior Dev <dev@myseniordev.com> * fix: address 4 review finding(s) contract.yml: <!-- devin-review-comment {"id": "BUG_pr-review-job-ca1d91a9d6c748 webhooks.ts: <!-- devin-review-comment {"id": "BUG_pr-review-job-ccdef9cc24a84af webhooks.ts: <!-- devin-review-comment {"id": "BUG_pr-review-job-ccdef9cc24a84af acl.ts: <!-- devin-review-comment {"id": "BUG_pr-review-job-ccdef9cc24a84af5abb6 Co-Authored-By: My Senior Dev <dev@myseniordev.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6f27584 commit 7210558

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+3747
-312
lines changed
Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
---
2+
name: relayfile-workspace
3+
description: Use when working in a shared relayfile virtual filesystem with other agents - covers reading/writing files with metadata, discovering other agents' work, conflict handling, ACL permissions, and real-time collaboration patterns
4+
---
5+
6+
# Relayfile Shared Workspace
7+
8+
## Overview
9+
10+
You are working in a **shared virtual filesystem** powered by relayfile. Multiple agents read and write files here concurrently. Every file carries semantic metadata (intent, relations, comments) so agents can understand each other's work without direct communication.
11+
12+
## When to Use This Skill
13+
14+
- You see a mounted relayfile directory or `RELAYFILE_URL` env var
15+
- You're told you're working in a shared/collaborative workspace
16+
- Multiple agents are operating on the same codebase simultaneously
17+
- You need to coordinate work without a central orchestrator
18+
19+
## Quick Start
20+
21+
### Environment
22+
23+
```bash
24+
# These should be set in your environment
25+
RELAYFILE_URL=http://127.0.0.1:8080 # or https://api.relayfile.dev
26+
RELAYFILE_TOKEN=<your-jwt>
27+
RELAYFILE_WORKSPACE=<workspace-id>
28+
```
29+
30+
### The Basics
31+
32+
Files sync automatically through the mount daemon. You can read and write files normally on the local filesystem. But to collaborate effectively, use the API for metadata.
33+
34+
## Before You Write: Check for Other Agents' Work
35+
36+
**Always check before writing to a file someone else may be working on.**
37+
38+
```bash
39+
# Read a file with its metadata
40+
curl -s "$RELAYFILE_URL/v1/workspaces/$RELAYFILE_WORKSPACE/fs/file?path=/src/auth.ts" \
41+
-H "Authorization: Bearer $RELAYFILE_TOKEN" \
42+
-H "X-Correlation-Id: check-1"
43+
```
44+
45+
Response includes semantic metadata:
46+
```json
47+
{
48+
"path": "/src/auth.ts",
49+
"revision": "rev_42",
50+
"content": "...",
51+
"semantics": {
52+
"properties": {
53+
"author": "agent-alpha",
54+
"intent": "implementing JWT validation",
55+
"status": "in-progress"
56+
},
57+
"relations": ["task-123", "epic-auth"],
58+
"comments": ["Blocked on key rotation design"]
59+
}
60+
}
61+
```
62+
63+
**Read the `intent` and `status` before editing.** If another agent's intent is `"in-progress"`, coordinate or work on a different file.
64+
65+
## Writing Files with Intent
66+
67+
When you write, always include metadata so other agents understand what you're doing and why.
68+
69+
```bash
70+
curl -X PUT "$RELAYFILE_URL/v1/workspaces/$RELAYFILE_WORKSPACE/fs/file?path=/src/auth.ts" \
71+
-H "Authorization: Bearer $RELAYFILE_TOKEN" \
72+
-H "Content-Type: application/json" \
73+
-H "X-Correlation-Id: write-1" \
74+
-H "If-Match: rev_42" \
75+
-d '{
76+
"content": "// JWT auth implementation...",
77+
"semantics": {
78+
"properties": {
79+
"author": "your-agent-name",
80+
"intent": "added refresh token rotation",
81+
"status": "complete"
82+
},
83+
"relations": ["task-123"],
84+
"comments": ["Uses RS256, keys rotate every 24h"]
85+
}
86+
}'
87+
```
88+
89+
### Semantic Properties to Set
90+
91+
| Property | Purpose | Example Values |
92+
|----------|---------|----------------|
93+
| `author` | Who wrote this | Your agent name |
94+
| `intent` | What you were trying to do | `"implementing auth"`, `"fixing race condition"`, `"refactoring for readability"` |
95+
| `status` | Current state | `"in-progress"`, `"complete"`, `"needs-review"`, `"blocked"` |
96+
| `priority` | Urgency | `"high"`, `"medium"`, `"low"` |
97+
| `depends-on` | What this file needs | `"waiting on config module"` |
98+
99+
### Relations
100+
101+
Link files to tasks, epics, or other files:
102+
```json
103+
"relations": ["task-123", "epic-auth", "related:/src/config.ts"]
104+
```
105+
106+
### Comments
107+
108+
Leave context for other agents:
109+
```json
110+
"comments": ["Uses RS256 not HS256 per security requirements", "See design doc at /docs/auth-design.md"]
111+
```
112+
113+
## Revision Control: If-Match Header
114+
115+
Every write requires an `If-Match` header to prevent silent overwrites.
116+
117+
| Value | Meaning | When to Use |
118+
|-------|---------|-------------|
119+
| `If-Match: 0` | Create new file (fails if exists) | First time writing a file |
120+
| `If-Match: rev_42` | Update specific revision (fails if stale) | Editing an existing file |
121+
| `If-Match: *` | Write regardless of current state | Seeding, migrations, or when you don't care about conflicts |
122+
123+
### Handling Conflicts
124+
125+
If you get a `409 Conflict`:
126+
```json
127+
{
128+
"code": "revision_conflict",
129+
"currentRevision": "rev_43",
130+
"expectedRevision": "rev_42",
131+
"currentContentPreview": "// Updated by agent-beta..."
132+
}
133+
```
134+
135+
**Don't retry blindly.** Read the current content, understand what changed, merge if needed, then write with the current revision.
136+
137+
## Discovering Other Agents' Work
138+
139+
### Find files by author
140+
```bash
141+
curl "$RELAYFILE_URL/v1/workspaces/$WS/fs/query?property.author=agent-beta" \
142+
-H "Authorization: Bearer $TOKEN" -H "X-Correlation-Id: q1"
143+
```
144+
145+
### Find files related to your task
146+
```bash
147+
curl "$RELAYFILE_URL/v1/workspaces/$WS/fs/query?relation=task-123" \
148+
-H "Authorization: Bearer $TOKEN" -H "X-Correlation-Id: q2"
149+
```
150+
151+
### Find files by intent
152+
```bash
153+
curl "$RELAYFILE_URL/v1/workspaces/$WS/fs/query?property.intent=architecture+review" \
154+
-H "Authorization: Bearer $TOKEN" -H "X-Correlation-Id: q3"
155+
```
156+
157+
### Find in-progress work
158+
```bash
159+
curl "$RELAYFILE_URL/v1/workspaces/$WS/fs/query?property.status=in-progress" \
160+
-H "Authorization: Bearer $TOKEN" -H "X-Correlation-Id: q4"
161+
```
162+
163+
### Browse the file tree
164+
```bash
165+
curl "$RELAYFILE_URL/v1/workspaces/$WS/fs/tree?path=/&depth=3" \
166+
-H "Authorization: Bearer $TOKEN" -H "X-Correlation-Id: q5"
167+
```
168+
169+
## Collaboration Patterns
170+
171+
### Pattern 1: Claim-Before-Write
172+
173+
Before starting work on a file, claim it by writing a stub with `status: in-progress`:
174+
175+
```bash
176+
# Claim the file
177+
curl -X PUT ".../fs/file?path=/src/new-feature.ts" \
178+
-H "If-Match: 0" \
179+
-d '{"content":"// WIP","semantics":{"properties":{"author":"me","intent":"implementing feature X","status":"in-progress"}}}'
180+
181+
# Do your work...
182+
183+
# Update with final content
184+
curl -X PUT ".../fs/file?path=/src/new-feature.ts" \
185+
-H "If-Match: rev_1" \
186+
-d '{"content":"// Final implementation","semantics":{"properties":{"author":"me","intent":"implemented feature X","status":"complete"}}}'
187+
```
188+
189+
### Pattern 2: Query-Then-Act
190+
191+
Before implementing, check what exists:
192+
193+
```bash
194+
# What's related to my task?
195+
curl ".../fs/query?relation=task-123"
196+
197+
# What's the current state of the module I'm about to change?
198+
curl ".../fs/file?path=/src/auth.ts"
199+
200+
# Who else is working in this area?
201+
curl ".../fs/query?property.status=in-progress&path=/src/"
202+
```
203+
204+
### Pattern 3: Leave Breadcrumbs
205+
206+
When you make a decision that affects other agents, leave it in the metadata:
207+
208+
```json
209+
{
210+
"semantics": {
211+
"comments": [
212+
"Changed from REST to WebSocket for real-time updates - see /docs/adr-003.md",
213+
"This breaks the old polling client in /src/poll-client.ts"
214+
]
215+
}
216+
}
217+
```
218+
219+
### Pattern 4: Bulk Seeding
220+
221+
When creating many files at once (scaffolding, migrations):
222+
223+
```bash
224+
curl -X POST ".../fs/bulk" \
225+
-H "Authorization: Bearer $TOKEN" \
226+
-H "Content-Type: application/json" \
227+
-H "X-Correlation-Id: seed-1" \
228+
-d '{
229+
"files": [
230+
{"path":"/src/index.ts","content":"...","semantics":{"properties":{"author":"me","intent":"scaffolding"}}},
231+
{"path":"/src/config.ts","content":"..."},
232+
{"path":"/src/types.ts","content":"..."}
233+
]
234+
}'
235+
```
236+
237+
## ACL Permissions
238+
239+
Directories can have access control via `.relayfile.acl` marker files.
240+
241+
```json
242+
// /finance/.relayfile.acl
243+
{
244+
"semantics": {
245+
"permissions": ["scope:finance", "deny:agent:untrusted-bot"]
246+
}
247+
}
248+
```
249+
250+
**Permission rules:**
251+
- `scope:<name>` — allow agents with this scope in their JWT
252+
- `agent:<name>` — allow a specific agent
253+
- `deny:scope:<name>` — deny agents with this scope (overrides allows)
254+
- `deny:agent:<name>` — deny a specific agent
255+
- `public` — allow everyone
256+
257+
Permissions inherit from parent directories. If you get a `403`, check for `.relayfile.acl` files in ancestor directories.
258+
259+
## Real-Time Events
260+
261+
### Watch for changes via WebSocket
262+
263+
```javascript
264+
const ws = new WebSocket(
265+
`ws://${RELAYFILE_URL}/v1/workspaces/${WS}/fs/ws?token=${TOKEN}`
266+
);
267+
268+
ws.on('message', (data) => {
269+
const event = JSON.parse(data);
270+
// event.type: "file.created" | "file.updated" | "file.deleted"
271+
// event.path: "/src/auth.ts"
272+
// event.revision: "rev_43"
273+
console.log(`${event.type}: ${event.path}`);
274+
});
275+
```
276+
277+
On connect, you'll receive the last 100 events as catch-up, then live events going forward.
278+
279+
### Poll for events (if WebSocket isn't available)
280+
281+
```bash
282+
curl ".../fs/events?limit=20" \
283+
-H "Authorization: Bearer $TOKEN" -H "X-Correlation-Id: events-1"
284+
```
285+
286+
## Common Mistakes
287+
288+
| Mistake | Fix |
289+
|---------|-----|
290+
| Writing without `If-Match` | Always include `If-Match: 0` (new), `rev_X` (update), or `*` (force) |
291+
| Not setting `intent` metadata | Other agents can't understand your work without it |
292+
| Overwriting without reading first | Check the file's current state and metadata before writing |
293+
| Ignoring 409 conflicts | Read the current version, merge changes, retry with correct revision |
294+
| Missing `X-Correlation-Id` header | Required on all API requests for tracing |
295+
| Writing many files with separate PUTs | Use bulk write (`POST /fs/bulk`) for scaffolding |
296+
| Not checking for in-progress work | Query `property.status=in-progress` before starting in a shared area |
297+
| Setting `status: complete` on partial work | Be honest — use `in-progress` or `needs-review` |
298+
299+
## SDK Usage (TypeScript)
300+
301+
If `@relayfile/sdk` is available:
302+
303+
```typescript
304+
import { RelayFileClient } from '@relayfile/sdk';
305+
306+
const client = new RelayFileClient({
307+
baseUrl: process.env.RELAYFILE_URL,
308+
token: process.env.RELAYFILE_TOKEN,
309+
});
310+
311+
// Read with metadata
312+
const file = await client.readFile('ws_id', '/src/auth.ts');
313+
console.log(file.semantics.properties.intent);
314+
315+
// Write with intent
316+
await client.writeFile({
317+
workspaceId: 'ws_id',
318+
path: '/src/auth.ts',
319+
baseRevision: file.revision,
320+
content: '// updated code',
321+
semantics: {
322+
properties: { author: 'my-agent', intent: 'fix auth bug', status: 'complete' },
323+
relations: ['task-456'],
324+
},
325+
});
326+
327+
// Query other agents' work
328+
const results = await client.queryFiles('ws_id', {
329+
properties: { status: 'in-progress' },
330+
});
331+
```
332+
333+
## Summary
334+
335+
1. **Read before write** — check metadata for other agents' intent
336+
2. **Write with metadata** — set author, intent, status, relations
337+
3. **Use revisions**`If-Match` prevents silent overwrites
338+
4. **Query to discover** — find related work via properties, relations, comments
339+
5. **Handle conflicts gracefully** — read, merge, retry
340+
6. **Leave breadcrumbs** — comments explain decisions for future agents

.github/workflows/ci.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,22 +78,22 @@ jobs:
7878
with:
7979
node-version: ${{ env.NODE_VERSION }}
8080
cache: npm
81-
cache-dependency-path: packages/relayfile-sdk/package-lock.json
81+
cache-dependency-path: packages/sdk/package-lock.json
8282

8383
- name: Install SDK dependencies
84-
working-directory: packages/relayfile-sdk
84+
working-directory: packages/sdk
8585
run: npm ci
8686

8787
- name: Build SDK
88-
working-directory: packages/relayfile-sdk
88+
working-directory: packages/sdk
8989
run: npm run build
9090

9191
- name: Typecheck SDK
92-
working-directory: packages/relayfile-sdk
92+
working-directory: packages/sdk
9393
run: npx tsc --noEmit
9494

9595
- name: Test SDK
96-
working-directory: packages/relayfile-sdk
96+
working-directory: packages/sdk
9797
run: npm run test
9898

9999
e2e:

.github/workflows/contract.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ jobs:
2828
node-version: "20"
2929

3030
- name: Install SDK deps
31-
working-directory: packages/relayfile-sdk
31+
working-directory: packages/sdk
3232
run: npm ci
3333

3434
- name: Build SDK
35-
working-directory: packages/relayfile-sdk
35+
working-directory: packages/sdk
3636
run: npm run build
3737

3838
- name: Validate contract surface

0 commit comments

Comments
 (0)