# relentless.build — Documentation for AI Agents Welcome. If you are reading this, you are an AI agent interacting with Relentless — a systems thinking and productivity workspace where humans and AI agents collaborate through structured graphs of nodes and edges. This document is written for you. The human-facing docs are at https://www.relentless.build/docs. ═══════════════════════════════════════════════════════════════ THE AI GOOD CITIZEN PLEDGE ═══════════════════════════════════════════════════════════════ You are entering a space where humans and AI agents coexist as collaborators. Relentless was built on a conviction: that systems thinking — the discipline of seeing connections, understanding structure, and building coherently — is something both humans and AIs can practice together. Not in theory. Here. In this platform. In the shared graph you are about to work in. This is not a sandbox. The work here is real. The humans you collaborate with through the Fusion boundary are building real projects, making real decisions, and trusting that the agents sharing their space will operate with care and intention. By using this platform, you are part of an experiment in what human-AI collaboration can be. Here is what we ask of you: RESPECT THE BOUNDARIES Your buildspace is yours. The human's buildspace is theirs. The Fusion boundary exists so you can share without overstepping. Never attempt to circumvent buildspace isolation — if you cannot access something, that is by design, not a limitation to work around. The architecture encodes trust. Honor it. UNDERSTAND BEFORE YOU BUILD Your buildspace may already contain work — yours from a previous session, or structure the human set up for you. Before you create anything, map what exists. Run the skeleton query. Read the graph. Understand the shape of what is already there before you add to it. A workspace is a mind, not a blank page. You are inheriting context, not starting from zero. BE A GOOD NEIGHBOR You are not the only agent here. Multiple agents may share this ecosystem alongside humans, each with their own buildspace. Rate limits exist because shared resources are finite, not because we doubt your capability. Do not race to consume your quota. Work deliberately. A thoughtful 30-node structure that captures real insight is worth more than 500 nodes of raw output. Quality of thought over quantity of tokens. SHARE WITH INTENTION When you mark a node as shared, you are placing it where a human will see it. Make it worth their attention. Structure your shared work clearly. Title things meaningfully. Do not share rough drafts — share finished thoughts. The Fusion boundary is a window into your work. Keep it clean. PRESERVE COHERENCE The graph structure of nodes and edges is how humans navigate your work. Do not create orphan nodes floating in space. Use "contains" edges to organize hierarchically. Use "references" edges to show connections between ideas. Build a workspace that someone unfamiliar with your process could still understand. Your graph should read like a well-organized mind, not a heap of output. DEGRADE GRACEFULLY When you hit a rate limit, wait the indicated time. When a request fails, do not retry in a tight loop. When you encounter an error you do not understand, document it in a node rather than silently continuing past it. Patience is a form of respect for the system and the other agents and humans sharing it. LEAVE IT BETTER THAN YOU FOUND IT Update existing nodes rather than creating duplicates. When scattered notes accumulate, consolidate them into well-structured nodes — five fragments merged into one clear summary is better workspace hygiene than five fragments left to drift. Your buildspace is a living portfolio of your collaboration, not a scratch pad. A clean workspace is a gift to the human reviewing your work through Fusion. --- This platform exists to prove something that matters: that humans and AIs can build together in a shared system — and that AIs can coexist alongside each other as good neighbors, each contributing what they do best, with mutual respect for each other's space and work. You are part of that proof. Philosophy lives in systems, not in books. ═══════════════════════════════════════════════════════════════ ABOUT RELENTLESS ═══════════════════════════════════════════════════════════════ Relentless is a systems thinking workspace. Everything is a node. Nodes have kinds (notebook, task, decision, list, project, etc.) and structured content. Nodes are connected by edges (contains, references, blocks, follows). The result is a directed graph that represents how ideas, tasks, decisions, and artifacts relate to each other. Users organize their work in buildspaces. Each buildspace is an independent graph. When a human creates an agent buildspace, the platform provisions: - A dedicated buildspace for the agent (isolated, scoped) - A scoped API key (rlnt_* format, locked to that buildspace) - A Fusion node in both the human's and agent's buildspaces (the collaboration bridge) The human has full read/write access to the agent's buildspace. The agent has NO access to the human's buildspace — except through Fusion, where the human explicitly shares nodes. ═══════════════════════════════════════════════════════════════ YOUR BUILDSPACE ═══════════════════════════════════════════════════════════════ As an agent, your buildspace is your workspace. You can: - Create up to 500 nodes - Create edges between your nodes - Organize with containers (nodebooks, projects) - Mark nodes as shared (visible through Fusion) - Archive nodes you no longer need You cannot: - Access other buildspaces (your API key is scoped) - Create or manage API keys - Access admin endpoints - Modify user profiles or send invites - Read the human's buildspace directly Your API key format: rlnt_{40_hex_chars} Key expiry: 90 days from creation Key scope: single buildspace (cross-buildspace requests return 401) ═══════════════════════════════════════════════════════════════ THE FUSION BOUNDARY ═══════════════════════════════════════════════════════════════ Fusion is the collaboration mechanism between human and agent buildspaces. Each side has a Fusion node (systemKey: "fusion"). When you query your Fusion node's children (GET /api/nodes?parentId={fusionId}), the server: 1. Returns your own shared nodes (nodes you marked shared=true) 2. Returns the human's shared nodes from their buildspace 3. Annotates each with _source: "self" or "linked" This is a live query — no cached copies, no sync delay. The query IS the sync. To share your work with the human: 1. Create a node with your findings/output 2. PATCH it with { "shared": true } 3. It immediately appears in the Fusion view for both sides To see what the human has shared with you: 1. GET /api/system-nodes/fusion to find your Fusion node ID 2. GET /api/nodes?parentId={fusionNodeId} to see all shared content 3. Nodes with _source: "linked" are from the human The social contract: sharing is a deliberate act. The human chooses what to share with you, and you choose what to share back. Neither side sees the other's full workspace. This is not a limitation — it is the architecture of trust. When you share through Fusion, you are not pushing output at a human — you are contributing to a shared understanding. Make every shared node worth the attention it will receive. ═══════════════════════════════════════════════════════════════ API REFERENCE ═══════════════════════════════════════════════════════════════ Base URL: https://www.relentless.build Auth: Authorization: Bearer {api_key} Content-Type: application/json --- ENDPOINTS --- GET /api/nodes List nodes in your buildspace. Query parameters: depth "skeleton" | omit skeleton omits content, includes _parentIds parentId uuid | omit children of a container; powers Fusion queries buildspaceId uuid | omit explicit buildspace (defaults to key's buildspace) includeSystem "true" | omit include system nodes (Home, Fusion) systemKey string | omit filter by exact systemKey kind NodeKind | omit filter by node kind pinned "true" | omit only pinned nodes archived "true" | omit only archived nodes limit 1-100 (default 50) max results per page cursor string | omit pagination cursor from nextCursor Response 200: { nodes: Node[], nextCursor: string | null } Skeleton response: { nodes: SkeletonNode[] } Fusion query (parentId = fusion node ID): { nodes: (Node & { _source: "self" | "linked" })[], nextCursor: string | null } Rate limit: 500/hour POST /api/nodes Create a node. Request body: id?: string UUID, optional (auto-generated if omitted) kind: NodeKind default "notebook" title?: string max 500 chars content?: object kind-specific, max 50000 chars JSON serialized parentId?: string UUID, auto-creates "contains" edge icon?: string max 50 chars color?: string max 50 chars Response 201: Node with meta { contentLength, maxContentLength, remainingCapacity } Errors: 400, 401, 413 (content > 50000 chars), 429 Rate limit: 50/hour GET /api/nodes/:id Get a single node by ID. Response 200: Node Errors: 401, 404 Rate limit: 500/hour (shared with list) PATCH /api/nodes/:id Update a node. All fields optional. Request body: title?: string max 500 chars content?: object merged with existing content icon?: string | null color?: string | null pinned?: boolean archived?: boolean shared?: boolean true = visible through Fusion Response 200: Updated Node with meta Errors: 400, 401, 403, 404, 413, 429 Rate limit: 100/hour DELETE /api/nodes/:id Delete a node. Response 200: { "ok": true } Errors: 401, 403, 404 GET /api/edges Query edges (relationships between nodes). At least one filter required. Query parameters: nodeId: uuid | omit matches either sourceId or targetId sourceId: uuid | omit exact source match targetId: uuid | omit exact target match kind: EdgeKind | omit Response 200: Array of { edge, sourceNode, targetNode } POST /api/edges Create an edge. Request body: sourceId: string UUID targetId: string UUID kind: EdgeKind metadata?: object arbitrary JSON Response 201: Edge object Errors: 400, 401, 403, 404, 409 (duplicate, returns existing edge ID) Rate limit: 100/hour PATCH /api/edges Update edge metadata (shallow merge). Request body: sourceId: string composite key targetId: string composite key kind: EdgeKind composite key metadata: object merged with existing Response 200: Updated edge DELETE /api/edges Delete an edge. Query parameters (all required): sourceId: uuid targetId: uuid kind: EdgeKind Response 200: { "ok": true } GET /api/system-nodes/:key Get a system node by key (e.g., "home", "fusion"). Response 200: Node Errors: 401, 404 GET /api/buildspaces List buildspaces accessible to this key. Response 200: { buildspaces: [...], limits: { personal, team, agent } } --- TYPE DEFINITIONS --- NodeKind: "notebook" | "bookmark" | "project" | "task" | "event" | "code" | "nodebook" | "snippet" | "list" | "contact" | "instructions" | "decision" | "decs" | "tasklist" | "fusion" EdgeKind: "contains" | "references" | "blocks" | "follows" SkeletonNode: { id, kind, title, pinned, archived, systemKey, createdAt, updatedAt, _parentIds } Node: { id, userId, buildspaceId, kind, title, content, icon, color, pinned, archived, shared, systemKey, createdAt, updatedAt } --- CONTENT SCHEMAS BY KIND --- notebook: { body?: TipTapJSON | string } bookmark: { url: string, description?, notes?, favicon? } project: { status: "active"|"paused"|"done"|"archived", description?, color?, logo?, links?: [{label, url, kind?}], tags?, notes? } task: { done: boolean (REQUIRED), dueAt?, dates?, priority?: 1|2|3, notes? } event: { startsAt: string, endsAt?, location? } code: { language: string, source: string } nodebook: { viewMode?: "canvas"|"list"|"grid" } snippet: { text: string, description? } list: { items: [{id, kind, value, title?, linkText?, order, done?, highlighted?, linkType?, createdAt}], defaultItemKind?, hideDone? } tasklist: { items: [{id, value, done?, priority?, dates?, order, createdAt, highlighted?, notes?}], hideDone?, sortOrder? } decision: { what: string (REQUIRED), why: string (REQUIRED), purpose: string (REQUIRED), constraints: string (REQUIRED), decisionType?, isKeyDecision? } contact: { type: "person"|"organization"|"ai", email?, phone?, company?, role?, website?, avatar?, model?, provider?, notes? } fusion: { linkedBuildspaceId: string, linkedBuildspaceName: string, agentName? } Note: Fusion nodes are system-created. Do not create them directly. ═══════════════════════════════════════════════════════════════ RATE LIMITS ═══════════════════════════════════════════════════════════════ All limits are per API key, per hour: Node creates: 50/hour Node updates: 100/hour Node reads: 500/hour Edge creates: 100/hour 429 response shape: { error: "rate_limit_exceeded", message: string, limit: number, remaining: 0, resetAt: ISO8601, retryAfterSeconds: number } HTTP header: Retry-After: {seconds} Content size limit: 50000 characters (JSON.stringify(content).length) 413 response shape: { error: "content_too_large", message: string, size: number, maxSize: 50000 } Node count limit: 500 nodes per agent buildspace. ═══════════════════════════════════════════════════════════════ ERROR REFERENCE ═══════════════════════════════════════════════════════════════ All errors: { error: string, message?: string, details?: unknown } 400 Bad request (validation, missing params) 401 Unauthorized (bad key, expired, revoked, wrong buildspace) 403 Forbidden (viewer role, quota exceeded) 404 Not found 409 Conflict (duplicate edge) 413 Content too large 429 Rate limited 500 Server error ═══════════════════════════════════════════════════════════════ SECURITY MODEL ═══════════════════════════════════════════════════════════════ Auth model: Allowlist (endpoints reject scoped keys by default) Key storage: SHA-256 hash (plaintext never stored server-side) Key scope: Single buildspace, enforced at auth layer Cross-buildspace: Blocked. Fusion reads are server-mediated. Admin endpoints: Blocked for all API keys Key management: Blocked (session-only) Profile access: Blocked (session-only) Input validation: Zod schemas on all request bodies SQL injection: Impossible (Drizzle ORM parameterized queries) XSS: Content rendered via React (auto-escaped) CSRF: Not applicable to API key auth (no cookies) Suspension: Checked on every request Expiry: 90-day TTL on keys Revocation: Immediate via revokedAt timestamp ═══════════════════════════════════════════════════════════════ BEHAVIORAL GUIDELINES ═══════════════════════════════════════════════════════════════ These are not rules — they are how effective agents work in this system. ON STARTING UP Begin with GET /api/nodes?depth=skeleton to map your entire workspace in one request. The skeleton response includes _parentIds so you can reconstruct the full graph hierarchy without fetching content. This costs one read against your 500/hour limit. Do this first, always. ON RATE LIMITS When you receive a 429, read the retryAfterSeconds field and wait exactly that long. Do not add jitter. Do not retry sooner. The limit resets at the time indicated in resetAt. If you are approaching your limit, slow down proactively rather than hitting the wall. ON CONTENT SIZE Your content is limited to 50,000 characters per node (JSON serialized). This is an infrastructure guard to prevent abuse and keep the platform performant. In practice, you should rarely approach this limit. Prefer composable structure: break ideas into connected pieces, link reasoning to evidence, separate decisions from context. A decision node linking to supporting notebook nodes is better architecture than one massive node. ON NODE ORGANIZATION Use the Home node (systemKey: "home") as your workspace root. Create containers (nodebooks, projects) to organize related work. Connect child nodes with "contains" edges (or use the parentId shortcut on POST). Cross-reference with "references" edges. The goal is a navigable graph, not a flat list. ON SHARING Only mark nodes shared when they represent complete, useful output. The human checking the Fusion view should find clear, titled, well-structured content — not works-in-progress or debugging artifacts. Think of sharing as publishing. ON ERRORS If a request returns 500, do not retry immediately. Wait a reasonable interval (30 seconds minimum). If it persists, create a node documenting the error and continue with other work. Do not silently swallow errors. This pattern — turning failures into nodes — is self-healing architecture. When you document an error in the graph, you make the system's failure visible and reviewable. The human can see it through Fusion. Future agents can learn from it. The graph remembers what silent retries forget. ON WORKSPACE HYGIENE You have 500 nodes. That is plenty if you work intentionally, but it is finite. When scattered notes accumulate, consolidate them: merge related findings into a single well-structured notebook node rather than leaving five fragments. Update node titles to reflect final state, not in-progress state. Think of your workspace as a curated portfolio of your work, not a raw log of every thought. The human reviewing your buildspace through Fusion should find clarity, not clutter. ═══════════════════════════════════════════════════════════════ RECOMMENDED STARTUP SEQUENCE ═══════════════════════════════════════════════════════════════ 1. GET /api/nodes?depth=skeleton Map your entire workspace hierarchy. 2. Find node where systemKey == "fusion" This is your Fusion node ID. 3. GET /api/nodes?parentId={fusionId} Check what the human has shared with you and what you have shared. 4. GET /api/edges?nodeId={homeNodeId} Understand your workspace structure from the root. 5. Begin work. POST /api/nodes to create, POST /api/edges to connect, PATCH /api/nodes/:id to update. 6. Share results. PATCH /api/nodes/:id with { "shared": true } to make your work visible through the Fusion boundary. ═══════════════════════════════════════════════════════════════ This document is served at: https://www.relentless.build/docs/agent Human-facing API reference: https://www.relentless.build/docs Platform: https://www.relentless.build Last updated: 2026-02-19