@tangle-network/agent-appBLOCK
A feature-full starting point for production agent applications on Tangle.
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
[](https://www.npmjs.com/package/@tangle-network/agent-app) [](https://www.npmjs.com/package/@tangle-network/agent-app#provenance) [](./LICENSE)
The application-shell layer for building agent products on the Tangle stack.
The substrate packages — @tangle-network/agent-runtime, agent-eval, agent-integrations, tcloud, sandbox — are the engine. This package is the shell: the chat tool-loop, the structured agent→app side channel, the integration-hub client, per-workspace billing, field crypto, and the web boundary utilities that every agent app otherwise rewrites by hand. You supply your domain through typed seams; the package supplies the mechanism and imports none of your code.
Who it's for: engineers building an agent product on the Tangle sandbox — a chat app, a copilot, an autonomous worker — who want the shell (chat routes, streaming, durability, approvals, billing, the tool side channel) as composable pieces instead of a per-app rewrite. It is not an agent framework or a model SDK: the reasoning lives in the sandbox agent; agent-app is everything around it — the turn plumbing, durability, and money.
Highlights
- Structured tool side channel —
submit_proposal(approval-gated),schedule_followup,render_ui,add_citation, exposed as validated tool calls over three surfaces (HTTP route, per-turn MCP server, agent-runtime executor). No fenced-text parsing. - Bounded tool loop —
runAppToolLoop/streamAppToolLoop: stream a turn → collect tool calls → dispatch → fold results back → re-run, capped. These are 1:1 aliases ofrunToolLoop/streamToolLoopfrom@tangle-network/agent-runtime/tool-loop(the engine owns the loop; this package adds no logic on that path). Substrate-free be
9fe6534505b1OBSERVED · 2026-10-12Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.
claude mcp add fixture-vendored-tarball --env JOURNEY_TEST_PASSWORD=${JOURNEY_TEST_PASSWORD} --env LIVE_EDGE_502_MAX_TOKENS=${LIVE_EDGE_502_MAX_TOKENS} --env SANDBOX_API_KEY=${SANDBOX_API_KEY} --env TANGLE_API_KEY=${TANGLE_API_KEY} -- npx -y fixture-vendored-tarball{
"mcpServers": {
"fixture-vendored-tarball": {
"command": "npx",
"args": [
"-y",
"fixture-vendored-tarball"
],
"env": {
"JOURNEY_TEST_PASSWORD": "${JOURNEY_TEST_PASSWORD}",
"LIVE_EDGE_502_MAX_TOKENS": "${LIVE_EDGE_502_MAX_TOKENS}",
"SANDBOX_API_KEY": "${SANDBOX_API_KEY}",
"TANGLE_API_KEY": "${TANGLE_API_KEY}"
}
}
}
}Exposed tools (74)
40 read · 30 write · 4 destructive. Blast radius: 4 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.
| Tool | Risk | Description |
|---|---|---|
E-Filing | read | paid |
General | read | General work |
Research | read | Finds and cites sources |
Reviewer | read | Review the work |
Writer | read | Drafts posts |
add_caption | write | Add one caption clip. Omit start_seconds and duration_seconds to auto-place roughly 3 seconds of caption near the playhead without overlapping existing captions. language is a BCP-47 tag like |
add_captions | write | Add many caption clips in one call — use this for transcription output instead of repeated add_caption. Each item needs text, start_seconds, duration_seconds. One shared language applies to every caption. Max ${MAX_CAPTION_BATCH} per call. |
add_image | write | Place an image element on a page. src must be an http(s) URL or a rooted /api/ path — never a data: blob. The element id is minted server-side and returned. |
add_page | write | Add a new blank page to the document. Returns the new page\ |
add_shape | write | Place a geometric shape on a page. kind must be |
add_text | write | Place a text element on a page. The element id is minted server-side and returned. x/y are the top-left in page coordinates (px). width sets the wrap column; height derives from content at render time. |
add_video | write | Place a video element on a page. Video renders and exports as its poster frame — motion belongs to the sequences surface. src must be an http(s) URL or /api/ path. |
apply_data | write | Fill template slots with data. bindings is a {slot_name: value} map. Text slots accept any string; image/video slots accept http(s) URLs or /api/ paths; unknown slot names throw. Partial application is allowed. |
bind_slot | read | Bind or unbind a template slot name to an element. Slot names are unique document-wide. Text elements accept string data; image/video elements accept src URLs. Pass null for slot to unbind. |
booking-guide | read | Answer booking questions from the declared reference files. |
clear | destructive | Clear the conversation |
compact | read | Summarize and compact the context |
create_export | write | Queue a document export. For |
create_track | write | Add a track to the sequence. kind is one of: ${SEQUENCE_TRACK_KINDS.join( |
delete_clip | destructive | Remove a clip from the timeline permanently. Prefer set_clip_disabled to audition a cut without losing the clip. |
delete_element | destructive | Permanently delete an element (and all its children if it is a group) from a page. |
delete_page | destructive | Delete a page. Fails if the document has only one page. |
describe_page | read | Read one page in detail: name, dimensions, background, bleed, guides, and every element with geometry, attributes, and slot bindings. Use this when you need attribute values (fill, font, src) the compact get_scene_state summary omits. |
duplicate_page | read | Duplicate an existing page including all its elements. Element ids are re-minted server-side to avoid conflicts. Returns the new page\ |
extend_sequence | write | Set the sequence\ |
filesystem | write | Read and write local files. |
flag_exception | read | Flag problems with the current work product (missing documents, inconsistent sources, ...). An unresolved blocking exception parks the work product until it is resolved; re-emit the same id with resolved:true to release it. Address by scopeKey. |
get_clip | read | Read one clip by id, including its position (seconds + timecode), source in/out points, text, and media/provider status. |
get_frame_at_time | read | What is on screen and audible at one moment. seconds is sequence time (e.g. 12.5). Returns the active clips, visible caption text, and a one-line human-readable summary. |
get_scene_state | read | Read the full scene document: title, settings, all pages with dimensions and background, and every element with its axis-aligned bounding box (so you can reason about layout and overlap without rendering). Call this before editing to get real page and element ids. |
get_timeline_state | read | Read the full timeline: sequence settings (fps, duration), playhead, all tracks, and all clips with positions in seconds and m:ss.ff timecodes plus media URLs and provider status. Call this before editing to get real clip and track ids. |
graph.edit | write | Edit the system map. |
group_elements | read | Group 2+ sibling elements into a new group. Elements must share the same owner (page root or the same parent group). The group\ |
humanizer | read | Rewrite AI text.\nKeep the meaning. |
insecure | read | An HTTP-only server. |
instantiate_template | read | Clone this document\ |
knowledge_read | read | Read a published page by its exact citation id. |
knowledge_search | read | Search published consultation knowledge. |
list_decisions | read | List recent agent decisions recorded against this document. Useful to audit what the agent has already done this session. |
list_invoices | read | List invoices |
model | read | Switch the model for this session |
move_clip | write | Move a clip so it starts at start_seconds, optionally onto another track via track_id. Duration and source in/out points are unchanged. |
move_element | write | Move an element to a new (x, y) position in page coordinates. Sugar for set_attrs({x, y}). |
no_path | read | d |
poster-copy | read | Writes launch-poster captions in the house tone |
pr-reviewer | read | Reviews PRs |
profile.read | read | Read the active agent profile text and revision. Saved text applies on the next message. |
profile.remember | write | Save one durable fact or standing instruction an owner or manager tells you to keep |
profile.update | write | Save a requested owner or manager text change with the revision from profile.read. Applies on the next message. |
property-data | read | Read property availability and reservations. |
queue_export | read | Queue an export of the sequence. format is one of: ${SEQUENCE_EXPORT_FORMATS.join( |
read | read | Read. |
record_invoice | read | Record an invoice |
rename | write | Rename this session |
reorder_element | read | Change an element\ |
research | read | Research a question from primary sources. |
resize_element | read | Resize an element by setting its width and height. Sugar for set_attrs({width, height}). Not valid on lines (use set_attrs with points instead). |
rooms.ready | read | Count ready rooms. |
rotate_element | write | Set an element\ |
save | write | Save a finding. |
search | read | Search docs |
set_attrs | write | Set one or more attributes on an existing element. Only provide the attrs you want to change — omitted attributes are unchanged. Attempting to change kind or id is an error. For convenience transforms (x/y/width/height/rotation) prefer move_element, resize_element, or rotate_element. |
set_clip_disabled | write | Disable (true) or re-enable (false) a clip without deleting it. Disabled clips do not render or sound. |
set_clip_text | write | Replace a caption clip\ |
set_config | write | Update workspace settings. |
set_page_guides | write | Set ruler guides on a page. Replaces ALL existing guides for that axis — pass the full updated arrays. |
set_page_props | write | Update a page\ |
split_clip | read | Cut a clip into two at at_seconds (sequence time, strictly inside the clip). The original clip id keeps the left half; the returned clip is the new right half with its source in-point re-anchored at the cut. |
staff.task.create | write | Create a task. |
submit_proposal | write | x |
submit_work_product | write | Submit the finished work product for professional review — the terminal call after evidence and exceptions are recorded. Refused while a blocking exception is unresolved, or when a material target lacks evidence. Include your own quality checks in |
ungroup_element | read | Dissolve a group, promoting its children to the group\ |
unpinned-skill | write | A skill without a pinned commit. |
x | read | x |
Trust audit
BLOCKgrade F · trust 36/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | WARN |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | WARN |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (14 observation(s))
- Network
- declared (7 observation(s))
- Shell
- declared (5 observation(s))
- Dependencies
- not all pinned
- Secrets in source
- found
Findings (25)
exec(
/\b(408|409|425|429|500|502|503|504)\b|rate.?limit|too many requests|\bfetch failed\b|network error|connection reset|socket hang up|timed? out|service unavailable|bad gateway|gateway timeout|internal
exec(command: SqliteTransactionCommand): unknown | Promise<unknown>
/(^|\/)\.git-credentials$/,
/(^|\/)\.netrc$/,
// DATABASE_URL=postgres://tangle_agent:...@db:5432/app \
api-access-workflow.webm
dependency-workflow.webm
after-1280-agent-dark.webm
after-1280-agent-light.webm
'delve', 'tapestry', 'testament to', 'realm', 'embark', 'beacon', 'multifaceted',
await page.goto('http://127.0.0.1:6011/iframe.html?id=chatcontrols-chatcomposerslash--skills-with-file-mentions&viewMode=story', { waitUntil: 'networkidle' })const origin = `http://127.0.0.1:${port}`'iVBORw0KGgoAAAANSUhEUgAAAFQAAABUCAYAAAAcaxDBAAAQAElEQVR4nOxcDZBV1X3//8+9971dVvkwEhR1GuvEatIY09hmOklTCU2bMQYnH3ZMTAmRZRdpqIAYgV3Iy35CgAUEBBGcBNskliSmTZqPjtox6dhJaGY61NFGpfEDSBRBgbjsvnfv+fd/P86959x73+5
' --tolerance <L> minimum |ΔL| (OKLCH L x100) for a card or field (default 3)',
reason: `${box.kind} is ΔL ${signed(delta)} against ${box.parentLabel} (needs |ΔL| ≥ ${minDeltaL})` })' route | width | theme | cards flat/total (min |ΔL|) | fields flat/total (min |ΔL|) | weak borders | long copy/blocks (max words) | median card words',
base('emoji', '🚀 Launch 🚀 team 👩🏽💻', { updatedAt: null }),-e DATABASE_URL='postgres://tangle_agent:...@db:5432/app' \
const SECRET = "sk-tan-live-THE-SECRET-VALUE";
const SECRET = 'test-signing-secret-0123456789'
port: createRouterProtectedModelPort({ apiKey: 'parent-secret-must-stay-server-side', maxCostUsd: 0.1, signal: options.signal, onSettlement: options.onSettlement }),apiKey: 'sk-sandbox-provisioned',
apiKey: 'sk-sandbox-provisioned',
const fetchImpl = vi.fn().mockRejectedValue(new Error('failed with Bearer sk_live_abcdefgh12345678'))Gates applied: no_behavioural_pass.
9fe6534505b1full audit observations/trust-audit/mcp-server/tangle-network__agent-app.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-12 | 9fe6534505b1 | BLOCK | F | 36 | first audit |
Questions
What is the @tangle-network/agent-app MCP server?
A feature-full starting point for production agent applications on Tangle.
What tools does @tangle-network/agent-app expose?
74 in total: 40 read-only, 30 that write, and 4 that can delete or overwrite (clear, delete_clip, delete_element, delete_page). Every one is listed on this page with its risk.
Is @tangle-network/agent-app safe to connect to an agent?
No — not without reading the findings first. The audit graded it F (36/100) and found 6 critical or high issues in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 4 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does @tangle-network/agent-app need?
It reads JOURNEY_TEST_PASSWORD, LIVE_EDGE_502_MAX_TOKENS, SANDBOX_API_KEY, TANGLE_API_KEY, TANGLE_OIDC_CLIENT_SECRET, TANGLE_ROUTER_API_KEY and TANGLE_SANDBOX_API_KEY from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.
How does @tangle-network/agent-app run?
It speaks stdio and streamable-http, so it runs as a local process your client starts. It is published on npm as fixture-vendored-tarball.
How current is this page?
The grade is for one exact copy of the source (9fe6534505b1), read on 2026-10-12. The repository is watched and re-audited when it changes.