[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-1712":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":8,"htmlUrl":8,"language":9,"languages":8,"totalLinesOfCode":8,"stars":10,"forks":11,"watchers":12,"openIssues":13,"contributorsCount":13,"subscribersCount":13,"size":13,"stars1d":13,"stars7d":13,"stars30d":14,"stars90d":13,"forks30d":13,"starsTrendScore":13,"compositeScore":15,"rankGlobal":8,"rankLanguage":8,"license":8,"archived":16,"fork":16,"defaultBranch":17,"hasWiki":16,"hasPages":16,"topics":18,"createdAt":8,"pushedAt":8,"updatedAt":19,"readmeContent":20,"aiSummary":21,"trendingCount":13,"starSnapshotCount":13,"syncStatus":12,"lastSyncTime":22,"discoverSource":23},1712,"tendril","serverless-dna\u002Ftendril","serverless-dna",null,"TypeScript",179,11,2,0,5,3.24,false,"main",[],"2026-06-12 02:00:31","# Tendril\n\nA self-extending agentic sandbox that demonstrates the **Agent Capability** pattern — where the model discovers, builds, and reuses tools autonomously across sessions.\n\nBuilt with [AWS Strands Agents SDK](https:\u002F\u002Fgithub.com\u002Fstrands-agents\u002Fsdk-typescript) and [Tauri](https:\u002F\u002Ftauri.app).\n\n## What it does\n\nYou ask Tendril to do something. It checks its capability registry. If a tool exists, it uses it. If not, it **writes one**, registers it, and executes it — all without asking. Next time you need the same thing, the tool is already there.\n\n```\nYou: \"fetch the top stories from Hacker News\"\n\nTendril:\n  → searchCapabilities(\"fetch url hacker news\")    # nothing found\n  → registerCapability(fetch_url, code)             # builds a tool\n  → execute(\"fetch_url\", {url: \"https:\u002F\u002F...\"})      # runs it by name\n  → \"Here are the top stories: ...\"\n\nYou: \"now fetch Lobsters and compare\"\n\nTendril:\n  → listCapabilities()                              # found: fetch_url ✓\n  → execute(\"fetch_url\", {url: \"https:\u002F\u002Flobste.rs\"})# runs it — no rebuild\n```\n\nThe registry grows with use. Every session is smarter than the last.\n\n## The Agent Loop\n\nThe core of Tendril is a Strands agent with **three bootstrap tools**. That's it — three tools to rule them all.\n\n### Where it lives\n\n```\ntendril-agent\u002Fsrc\u002F\n├── agent.ts              ← Agent configuration (Strands model + tools)\n├── index.ts              ← Orchestrator — wires loop to transport\n├── loop\u002F                 ← The agentic loop\n│   ├── tools.ts          ← 4 bootstrap tools in cycle order\n│   ├── prompt.ts         ← System prompt (autonomous behaviour rules)\n│   ├── registry.ts       ← Capability registry (index.json CRUD)\n│   └── sandbox.ts        ← Deno subprocess execution with sandboxing\n└── transport\u002F            ← Conversation framing + stream observation\n    ├── protocol.ts       ← ACP JSON-RPC over stdio\n    ├── stream.ts         ← SDK events → loop phases (think\u002Fact\u002Fobserve)\n    └── errors.ts         ← Provider error classification\n```\n\n### How it works\n\n**`agent.ts`** — Creates the Strands agent with a Bedrock model and three tools:\n\n```typescript\nimport { Agent } from '@strands-agents\u002Fsdk';\nimport { BedrockModel } from '@strands-agents\u002Fsdk\u002Fmodels\u002Fbedrock';\n\nconst agent = new Agent({\n  model: new BedrockModel({ modelId: '...', region: '...' }),\n  systemPrompt: TENDRIL_SYSTEM_PROMPT(workspacePath),\n  printer: nullPrinter,   \u002F\u002F suppress SDK stdout — we own the protocol\n  tools: [\n    listCapabilities(registry),\n    registerCapability(registry),\n    executeCode(registry, workspacePath, config),\n  ],\n});\n```\n\n**`index.ts`** — Observes the agentic loop and bridges it to the ACP protocol:\n\n```typescript\n\u002F\u002F The agentic loop runs inside agent.stream().\n\u002F\u002F We observe each phase and forward to the UI.\nfor await (const event of agent.stream(userText)) {\n  const { phase, event: e } = classifyEvent(event);\n  switch (phase) {\n    case 'think':   emitUpdate(handleThink(e));    break;  \u002F\u002F text delta\n    case 'act':     emitUpdate(handleAct(e));      break;  \u002F\u002F tool call\n    case 'observe': emitUpdate(handleObserve(e));  break;  \u002F\u002F tool result\n  }\n}\n```\n\n**`loop\u002Fprompt.ts`** — The system prompt that makes the agent autonomous:\n\n```\nBEFORE acting on any request:\n1. Call searchCapabilities(query) to check if a relevant tool exists\n2. If found: call loadTool(name) then execute(code, args)\n3. If NOT found: you MUST build the tool yourself.\n\nRULES:\n- NEVER ask \"would you like me to create a tool?\" — just build it.\n- If a tool fails, read the error, fix the code, and retry.\n- NEVER answer from training data when a tool could get live information.\n```\n\n### The \"too many tools\" solution\n\nMost agent frameworks give the model a big bag of tools and hope it picks the right one. Tendril inverts this — the model always sees exactly **three tools**. It searches a registry, builds what it needs, and the registry grows over time. The tool surface never changes; the capabilities do.\n\n## Architecture\n\n```\n┌─────────────────────────────────────────┐\n│ Tauri Shell (Rust)                      │\n│                                         │\n│  ACP Host ──stdin\u002Fstdout──► Agent       │\n│  (acp.rs)    NDJSON        (Node.js SEA)│\n│     │                         │         │\n│  Events  ◄── session\u002Fupdate ──┘         │\n│  (events.rs)                            │\n│     │                                   │\n│  Tauri Events ──►  React Frontend       │\n│                    (TailwindCSS v4)     │\n└─────────────────────────────────────────┘\n\nAgent internals:\n  Strands SDK ── BedrockModel ── Claude\n       │\n  4 bootstrap tools\n       │\n  ┌────┴────┐\n  │ Registry │ ←→ index.json + tools\u002F*.ts\n  └─────────┘\n       │\n  ┌────┴────┐\n  │ Sandbox  │ ←→ Deno subprocess (scoped permissions)\n  └─────────┘\n```\n\n**Communication**: JSON-RPC 2.0 over NDJSON (newline-delimited JSON) on stdin\u002Fstdout. The agent is a standalone process — the Tauri host spawns it as a sidecar.\n\n**Protocol**: Implements the [Agent Integrator Specification](docs\u002Fagent-integrator-spec.pdf) (ACP) — the same protocol used by Claude Code and similar agent hosts.\n\n## Tech Stack\n\n| Component | Technology |\n|-----------|-----------|\n| Desktop shell | Tauri 2.x (Rust) |\n| Frontend | React 18 + TailwindCSS v4 |\n| Agent | TypeScript (Node.js SEA binary) |\n| Agent framework | [@strands-agents\u002Fsdk](https:\u002F\u002Fgithub.com\u002Fstrands-agents\u002Fsdk-typescript) |\n| Inference | AWS Bedrock (Claude via Strands BedrockModel) |\n| Code sandbox | Deno (bundled, subprocess with permission flags) |\n| Protocol | JSON-RPC 2.0 \u002F NDJSON over stdio |\n\n## Prerequisites\n\n- **Node.js 22+** (for building the agent)\n- **Rust toolchain** (for Tauri)\n- **AWS credentials** configured for Bedrock access (`~\u002F.aws\u002Fcredentials`)\n\n## Quick Start\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Fserverless-dna\u002Ftendril.git\ncd tendril\nmake dev\n```\n\nThis will:\n1. Install dependencies (`npm install` for agent and UI)\n2. Build the agent (`esbuild` bundle)\n3. Download Deno (bundled as sidecar)\n4. Create sidecar shims with platform triple\n5. Launch Tauri dev mode\n\nOn first launch, pick a workspace folder. Configure your AWS profile and model in Settings.\n\n## Configuration\n\nAll settings live at `~\u002F.tendril\u002Fconfig.json`:\n\n```json\n{\n  \"workspace\": \"\u002FUsers\u002Fyou\u002Ftendril-workspace\",\n  \"model\": {\n    \"provider\": \"bedrock\",\n    \"modelId\": \"us.anthropic.claude-sonnet-4-5-20250514\",\n    \"region\": \"us-east-1\",\n    \"profile\": \"your-aws-profile\"\n  },\n  \"sandbox\": {\n    \"denoPath\": \"deno\",\n    \"timeoutMs\": 45000,\n    \"allowedDomains\": []\n  },\n  \"agent\": {\n    \"maxTurns\": 100\n  }\n}\n```\n\n`allowedDomains`: empty = unrestricted network. Set `[\"api.example.com\"]` to restrict.\n\n## Capability Registry\n\nCapabilities are stored in the workspace as plain files:\n\n```\n~\u002Ftendril-workspace\u002F\n  index.json          ← registry (name, triggers, suppression rules)\n  tools\u002F\n    fetch_url.ts      ← tool implementation (TypeScript, runs in Deno)\n    summarize_text.ts\n    parse_json.ts\n```\n\nEach capability has:\n- **name**: `snake_case` identifier\n- **capability**: one-sentence description\n- **triggers**: conversational signals that should invoke it\n- **suppression**: conditions that prevent invocation\n\nThe model writes these definitions. You can inspect, edit, or delete them — they're just files.\n\n## Makefile Targets\n\n```\nmake dev       Build agent + sidecars, launch Tauri dev\nmake build     Build agent (esbuild bundle)\nmake test      Run agent tests (vitest)\nmake lint      tsc --noEmit + cargo clippy\nmake fmt       cargo fmt --check\nmake check     Full quality gate (fmt + lint + test)\nmake release   Quality gate + cargo tauri build\nmake clean     Remove all build artifacts\n```\n\n## Project Structure\n\n```\ntendril\u002F\n  tendril-agent\u002F        TypeScript Strands sidecar\n    src\u002F                Agent source (see \"The Agent Loop\" above)\n    tests\u002F              vitest tests\n    package.json\n    sea-config.json     Node.js SEA build config\n\n  tendril-ui\u002F           Tauri + React desktop app\n    src\u002F                React components + hooks\n    src-tauri\u002F          Rust backend (ACP host, event forwarding)\n    package.json\n\n  docs\u002F                 Specs and reference implementations\n  specs\u002F                Feature specifications and plans\n  Makefile\n```\n\n## License\n\nMIT\n","Tendril 是一个自我扩展的代理沙箱，展示了代理能力模式，即模型能够自主发现、构建并在会话间重用工具。其核心功能在于通过检查能力注册表来确定是否已有适用工具；若无，则自动编写新工具并注册执行。这一过程完全无需用户干预，随着使用次数增加，每次会话都会变得更智能。技术上，Tendril 基于 AWS Strands Agents SDK 和 Tauri 构建，采用 TypeScript 语言开发。它特别适用于需要自动化处理任务且希望减少重复劳动的场景，如数据抓取、信息处理等。","2026-06-11 02:45:34","CREATED_QUERY"]