{
  "markdown": "<!-- okf\ntype: Index\ntitle: Namzu\ndescription: >-\n  An open-source agent platform for TypeScript. Ships an operator application,\n  a reusable kernel and optional runtimes for supervised agents with explicit\n  identity, budgets, permissions and pluggable durability. FSL-1.1-MIT,\n  converting to MIT two years after each release.\ntags: [readme, index, typescript, agent-platform]\nstatus: stable\ngenerated: { by: human:bahadirarda, at: 2026-08-07T00:00:00Z }\n-->\n\n<div align=\"center\">\n\n<h1>Namzu</h1>\n\n**An open-source agent platform for TypeScript.**\n\n[![License: FSL-1.1-MIT](https://img.shields.io/badge/license-FSL--1.1--MIT-blue.svg)](./LICENSE.md)\n[![npm @namzu/sdk](https://img.shields.io/npm/v/@namzu/sdk.svg?label=%40namzu%2Fsdk)](https://www.npmjs.com/package/@namzu/sdk)\n[![npm @namzu/cli](https://img.shields.io/npm/v/@namzu/cli.svg?label=%40namzu%2Fcli)](https://www.npmjs.com/package/@namzu/cli)\n\n[Install](#install) · [An agent is a folder](#or-dont-write-any-of-that--make-a-folder) · [What is inside](#what-is-inside-that-is-independently-hard) · [Packages](#the-packages) · [Docs](./docs/)\n\n</div>\n\n---\n\n## What this is\n\nAn agent that works in a demo is a loop around a model call. An agent that\nworks in production is that loop plus everything around it — a budget that\nstops it, an identity that attributes it, a boundary it cannot talk its way\npast, a record that can survive the process when durable stores are configured,\nand a way to shrink a conversation that is about to overflow without corrupting\nit.\n\nNamzu is the platform for those other things. Its `@namzu/sdk` kernel runs an\nagent the way an operating system runs a process: it is given an identity and a\nbudget, scheduled, checkpointed, and optionally confined by the sandbox a host\nsupplies. The kernel renders no UI, requires no database, hosts no service, and\nhas no preferred model vendor. Direct SDK consumers install only the driver\npackages they use; the CLI bundles its supported set.\n\n`@namzu/cli` is a terminal coding agent built entirely on that kernel, in this\nrepository, from the same public API you get. It exists as much to prove the\nkernel as to be used: every gap in the SDK showed up first as something the\nCLI had to work around.\n\n## Who it is for\n\nRead on if any of these is your afternoon:\n\n- The run has to be **attributable** — a tenant, a project, a session, and an\n  auditable trail of what it did and what it cost.\n- The run has to be **bounded** — tokens, money, wall clock, and iterations,\n  enforced rather than hoped for.\n- The run has to **survive** — a process restart, a deploy, an operator\n  pressing Ctrl-C, a question that needs a human before it can continue.\n- One agent has to **delegate** to another, and that is where it broke.\n- The model gets **tools**, and you would rather it not get your machine.\n- You are **multi-tenant**, and \"two customers in one process\" has to be a\n  property of the type system rather than a code review.\n\nRead something else if you want a chat interface by the end of the day. There\nis no UI here, no dashboard, no hosted anything. This is the layer underneath\nthat.\n\n## Install\n\nThe kernel runs standalone against a scriptable mock driver, so the first run\nneeds no key and no network:\n\n```bash\npnpm add @namzu/sdk zod@^3\n```\n\n<sub>The kernel bundles no runtime dependencies — `zod`, `zod-to-json-schema`\nand `@opentelemetry/api` are peer-declared so your lockfile owns the versions.\nPin `zod` to v3: that is the range the kernel is built against, and a bare\n`pnpm add zod` installs v4.</sub>\n\n```typescript\nimport { ProviderRegistry, runAgent } from '@namzu/sdk'\n\nconst { provider } = ProviderRegistry.create({ type: 'mock', responseText: 'Paris.' })\n\nconst { output, run, identity } = await runAgent({\n  provider,\n  model: 'mock-model',\n  prompt: 'What is the capital of France?',\n})\n\nconsole.log(output)          // 'Paris.'\nconsole.log(run.stopReason)  // 'end_turn'\nconsole.log(identity)        // { sessionId, threadId, projectId, tenantId }\n```\n\nThat is not a chat call with extra steps. It generated a session identity,\napplied the default budgets, ran the tool scheduler, wrote a checkpoint per\niteration, and left the whole run on disk under\n`.namzu/projects/<project>/sessions/<session>/runs/<run>/` — `run.json`,\n`messages.json`, `transcript.jsonl`, a human-readable `report.md`, and a\n`checkpoints/` directory.\n\n`identity` comes back so the next turn continues the same session:\n\n```typescript\nimport { createUserMessage } from '@namzu/sdk'\n\nconst second = await runAgent({\n  provider,\n  model: 'mock-model',\n  ...identity,\n  prompt: [...run.messages, createUserMessage('And of Japan?')],\n})\n```\n\nGive it tools and the same call runs a tool loop:\n\n```typescript\nimport { defineTool, ToolRegistry } from '@namzu/sdk'\nimport { z } from 'zod'\n\nconst tools = new ToolRegistry()\n\ntools.register(\n  defineTool({\n    name: 'get_weather',\n    description: 'Current weather for a city.',\n    inputSchema: z.object({ city: z.string() }),\n    category: 'network',\n    permissions: ['network_access'],\n    readOnly: true,\n    destructive: false,\n    concurrencySafe: true,\n    execute: async ({ city }) => ({\n      success: true,\n      output: `It is 17C and raining in ${city}.`,\n    }),\n  }),\n)\n\nconst { output } = await runAgent({\n  provider,\n  model: 'mock-model',\n  tools,\n  prompt: 'What is the weather in Paris?',\n})\n```\n\nA tool declares what it *is* — read-only or not, destructive or not, safe to\nrun concurrently or not, and which permissions it needs — because the\nscheduler, the permission gate and the operator prompt all have to ask those\nquestions, and a tool that will not answer them forces every one of them to\nassume the worst.\n\nTo talk to a real service, install a driver and swap the two lines that\nconstruct the provider. Nothing below them changes.\n\n```bash\npnpm add @namzu/sdk @namzu/ollama    # local, no key\n```\n\n### Or don't write any of that — make a folder\n\nAn agent can be a directory. `loadDirectory` reads a conventional folder into\nexactly the options `runAgent` already takes, so there is no second engine and\nnothing reachable only this way.\n\nThe smallest one that works is a folder with a file in it:\n\n```\nagent/\n└── instructions.md\n```\n\n```typescript\nimport { deriveRunOptions, loadDirectory, runAgent } from '@namzu/sdk'\n\nconst { manifest } = await loadDirectory('./agent')\nconst { output } = await runAgent(\n  deriveRunOptions(manifest, { provider, model: 'mock-model', prompt: 'Hi' }),\n)\n```\n\nEverything else is optional, and each slot buys one thing:\n\n```\nagent/\n├── instructions.md     the system prompt, used verbatim\n├── agent.ts            export default { model, temperature, maxIterations,\n│                         tokenBudget, timeoutMs, name, metadata } — all optional\n├── tools/              one file per tool, each default-exporting defineTool(...)\n├── skills/             one folder per skill\n└── agents/             one folder per delegate, same shape, one level deep\n```\n\n`instructions.md` is used verbatim, and it is one of **two** ways to shape an\nagent here. The other is the structured persona assembler, and the two are not\nrival subsystems — they fill one slot, with a plain system prompt taking\nprecedence over a persona. `assembleSystemPrompt(persona)` returns a string, so\nits output can simply be what `instructions.md` contains. A folder does not lose\nits skills by taking the simple route: the skills section is rendered either way.\nThe trade-off is set out in\nan agent can be a directory.\n\nA tool file is a normal module:\n\n```typescript\n// agent/tools/weather.ts\nimport { defineTool } from '@namzu/sdk'\nimport { z } from 'zod'\n\nexport default defineTool({\n  name: 'get_weather',\n  description: 'Current weather for a city.',\n  inputSchema: z.object({ city: z.string() }),\n  category: 'network',\n  permissions: ['network_access'],\n  readOnly: true,\n  destructive: false,\n  concurrencySafe: true,\n  execute: async ({ city }) => ({ success: true, output: `It is 17C in ${city}.` }),\n})\n```\n\nThat is the whole convention. A recent runtime imports the `.ts` directly, so\nthere is no build step; a project whose syntax it cannot read passes its own\n`importModule`.\n\n**Loading a folder does not have to run it.** Importing a module executes it —\na top-level side effect in `tools/search.ts` happens during the load, in your\nprocess, with your privileges. So the loader has a mode:\n`loadDirectory(dir, { modules: 'skip' })` imports **nothing**, and still returns\nthe full structure: every path, the instructions, the skills, duplicate\ndetection, and each file marked `not_loaded`. That is the mode for a CI check,\na file tree, or triage of a directory whose author is not you. Symlinks inside\na slot are refused rather than followed, for the same reason — the file that\ngets imported would not be the file that was listed.\n\nNothing is silently dropped. Every refusal comes back as a diagnostic naming\nits file and reason: a tool file with no default export, two tools claiming one\nname (neither is registered), an empty `instructions.md`, a nested directory\nthat was not scanned. `ok` tells you whether any of them was an error — scoped\nto the slots you asked for, so it never means more than it checked.\n\n**What the folder form does not do**, so you find out here rather than later:\n\n- **It is SDK-only today.** The terminal agent does not read an `agent/`\n  folder — it has its own project instructions and trust gate, and the two are\n  unrelated. Nothing auto-discovers: you pass the path.\n- **Config is static.** `agent.ts` exports a plain object, not a factory. Read\n  an environment variable inside it if you need to; there is no hook.\n- **Delegates go one level.** A delegate may not declare delegates of its own.\n- **A skipped load cannot be run.** `deriveRunOptions` throws on a\n  `modules: 'skip'` manifest rather than handing back an agent whose tools are\n  all missing for a reason unrelated to the project.\n- **The working directory becomes the folder itself**, not its parent, so file\n  tools are contained to the agent. Widening that is an explicit override.\n\n### The terminal agent\n\n```bash\n# Install it\ncurl -fsSL https://raw.githubusercontent.com/cogitave/namzu/main/install.sh | sh\n\n# Windows\nirm https://raw.githubusercontent.com/cogitave/namzu/main/install.ps1 | iex\n\n# Or, if you would rather not pipe a script into a shell\nnpm install -g @namzu/cli\n\n# Or run it once without installing\nnpx @namzu/cli\n```\n\nThe installer checks for Node 20+, installs the package, and then verifies the\nbinary answers before claiming success. If your global prefix is not writable\nit retries into `~/.namzu` and tells you the one line to add to your profile —\nit never re-runs itself with elevated privileges.\n\nBare `namzu` opens an interactive terminal agent. The same binary is\nscriptable: `namzu run` for a single headless prompt, `namzu run-stream` for\nnewline-delimited events a host UI can consume, `namzu history`,\n`namzu doctor`, `namzu upgrade`, `namzu skills`, and `namzu eval`, plus `namzu providers-json`\nand `namzu skills-json` for a host UI that wants the rosters as JSON. Run\n`namzu --help` for the current list.\n\nThe TUI names `namzu upgrade` when npm reports a newer version. The command\nupdates the npm-global prefix that owns the running package and verifies that\nexact package before claiming success; `namzu upgrade --check` is read-only.\n\nThree things it does on the way in are worth knowing, because they are the\ndifference between a toy and something you point at a real repository:\n\n- **A folder nobody has trusted is not one it runs in.** On launch in an\n  unfamiliar working directory it stops and asks, because reading, running\n  commands and editing files there is what it is about to be able to do.\n- **The repository gets to state how it wants work done.** An `AGENTS.md` is\n  read from the working directory upward to the repository root, outermost\n  first, so the file nearest the work has the final word. Before this existed\n  everything the agent was told was about the *user* and global to the\n  machine; a project that had written its conventions down had no way to be\n  heard short of pasting the file in every session.\n- **It connects to the tool servers you declare**, so the tools available in a\n  given checkout are that checkout's business rather than the binary's.\n\n## What is inside that is independently hard\n\nThe reason this repository is larger than a loop is that each of the following\nis a problem you hit at a specific hour of building an agent product, and each\none is a thing you would otherwise stop and solve yourself. Every item names\nthe file that implements it, because a README is a claim and the code is the\nevidence.\n\n**Shrinking a conversation without corrupting it.**\nThe window fills and something has to go, but you cannot simply drop the\noldest messages. An assistant turn that asked for a tool and the result that\nanswers it are a matched pair, and a provider rejects a conversation\ncontaining one without the other — so the naive trim turns a context problem\ninto a hard API error. `findDanglingMessages` scans for both halves of that\nbreak, and `findSafeTrimIndex` picks a cut that does not create one. The\nwindow size itself is resolved by longest-prefix match on the model id, with\na deliberately conservative default for an unrecognised model: compacting too\nearly costs one summarisation pass, and compacting too late ends the run with\nnothing recoverable.\n→ `packages/sdk/src/compaction/dangling.ts`, `compaction/context-window.ts`\n\n**A run that outlives the process that started it.**\nEach iteration writes a checkpoint carrying the history, the budgets, the\nworking state and the trace context. `resumeRun` joins one of those snapshots\nback onto a live loop in a *different* process. It returns three outcomes\nrather than a nullable run, because the two failures mean opposite things: \"no\ncheckpoint\" is a dead end, while \"parked awaiting a decision\" is the run\nworking exactly as designed and waiting for a human. On `SIGINT` or `SIGTERM`\nan opt-in emergency save writes the run out before the process leaves.\n→ `runtime/query/resume-run.ts`, `runtime/query/checkpoint.ts`, `manager/run/emergency.ts`\n\n**Delegation that cannot quietly corrupt itself.**\nWork is a five-layer hierarchy — project, topic, session, sub-session, run —\nand each layer's opaque UUID has its own nominal type, so handing a\nsession id to something expecting a run id does not compile. Depth and width\ncaps are checked *before* any write, and the width check plus the write that\ninvalidates it are held in one critical section keyed on the parent: without\nthat, two concurrent spawns both read the same count, both saw room, and a cap\nof N admitted N+1. Session ownership is a compare-and-set against the version\nthe *store* holds — previously two concurrent handoffs could both pass, both\nprovision a workspace, and one silently erase the other. Archiving a project\nrefuses rather than cascades while live sessions are attached, because closing\na workspace under a running agent abandons work whose owner is still watching.\nAnd a delegated task whose launching call already timed out still produced a\nresult somebody should see; the completion inbox is what stops it being\ndropped on the floor.\n→ `session/handoff/capacity.ts`, `manager/agent/lifecycle.ts`, `session/errors.ts`, `gateway/completion-inbox.ts`\n\n**A budget that survives being divided.**\nFive dimensions are checked every iteration — cancellation, wall clock, token\nbudget, cost, and iteration count — each producing a named stop reason rather\nthan an exception, with a warning tier before the hard stop so a run can react\nwhile it still can. Dividing that budget across a delegation tree is where it\ngets interesting.\nA child gets a slice of its parent's remaining tokens, computed inside the\nspawn lock so siblings queue instead of all reading the same untouched number,\ndebited only once provisioning commits so a rejected spawn costs nothing, and\n*refunded* on settle. The refund is the part that is easy to miss and\nexpensive to omit: without it the pool shrinks by the full allocation\nregardless of what the child spent, and ten delegations leave a parent with a\nthousandth of its budget. A spawn whose allocation rounds to zero is refused\noutright rather than granted, because zero means *unlimited* downstream — so\nthe naive arithmetic hands the most depleted parent in the tree an unbounded\nchild.\n→ `manager/agent/lifecycle.ts`, `run/LimitChecker.ts`\n\n**A refusal the model can actually act on.**\nA permission gate that answers only \"denied\" produces thrashing: the model\nrewords the same call and tries again, because nothing told it that retrying\nis pointless. Every rule here can describe itself in a sentence — which rule\nmatched, which argument, whether a different input could ever get through — and\nthat sentence goes back to the model inside the tool result. Approvals are\nscoped by the approver rather than fixed: a grant can cover one exact\ninvocation or an entire tool, and the key is built from arguments serialised\nwith sorted properties, so the same call never gets asked about twice merely\nbecause two fields swapped order. Grants live for the run and are never\npersisted.\n→ `verification/gate.ts`, `runtime/query/tool-grants.ts`\n\n**Content the agent must read but must not obey.**\nAnything a tool returns — a fetched page, another agent's output, a connector's\nprompt — is wrapped in an envelope that says whose words these are and that\nthey are material rather than instruction. Two details separate a boundary\nfrom a decoration, and both were missing the first time: the closing token is\nneutralised inside the body, so content carrying the delimiter cannot end the\nblock early and have the rest read as unlabelled instructions; and there is no\n\"already wrapped\" fast path, because that check is forgeable by text that\nmerely starts with the opening tag.\n→ `tools/untrusted-envelope.ts`\n\n**Isolation that tells you what it is not enforcing.**\nSandbox tiers do not all provide the same controls, and the honest table is\nkept in code: one environment enforces filesystem, network and process\nisolation; another enforces network and process only and reports\n`filesystem: false` **on purpose**, because it unshares a mount namespace\nwithout remounting anything and a private mount table is not confinement. If a\nrun requires a control the host cannot supply, the kernel refuses to start it\nrather than proceeding while the caller believes it is confined. A security\ncontrol that is accepted and silently not applied is worse than one that was\nnever offered.\n→ `sandbox/isolation.ts`\n\n**Provider differences that are really latent bugs.**\nSeveral services spell a model id the same way, ending in either a minor\nversion or an eight-digit release date. Three drivers had each written the\nsame matcher and all three read the date as the minor, so an id naming no\nminor compared as enormously *newer* — and every capability check keyed on\nthat comparison inverted, telling a model it supported features it does not.\nThere is now one parser, given the vocabulary by the driver that knows it.\nAlongside it: strict tool schemas are a *subset* of JSON Schema, and a single\nkeyword outside that subset makes a service reject the whole request rather\nthan degrade one field, so violations are found before the call; one tool\nschema is rendered once and converted per dialect at the driver; and a driver\nthat cannot honour a requested capability must refuse rather than drop it.\n→ `provider/model-version.ts`, `provider/strict-schema.ts`, `registry/tool/dialect.ts`, `provider/thinking-support.ts`\n\n**Correcting a run that is already going.**\nWatching an agent head the wrong way, the two obvious options are both bad:\ncancelling discards every tool result already paid for, and rejecting through\nthe review gate only works if a call happens to be pending and can only say\n\"no\" when you meant \"yes, but look at this first\". There is also no legal\nplace to insert a user message mid-batch — a tool call must be answered by its\nmatching result. So guidance rides on the tool result itself, the slot the\nmodel already reads for outcomes. It does not interrupt; the batch in flight\nfinishes and the note lands where the model looks next.\n→ `runtime/query/steering.ts`\n\n**Reading an agent directory you did not write.**\nA conventional `agent/` folder can contribute instructions, tools, skills and\nsub-agents. Loading one has a mode, because importing a module *runs* it — a\ntop-level side effect executes in your process with your privileges. `'skip'`\nimports nothing and still returns the full structural truth: every path, the\ninstructions, the skills, and duplicate detection. That is what a CI check, a\nfile tree, and triage of somebody else's directory all actually want.\n→ `directory/types.ts`, `directory/load.ts`\n\n## The packages\n\n`@namzu/sdk` is the kernel and has no workspace dependencies. Runtime extension\npackages depend on it through `peerDependencies`; the CLI is the composition\nroot and owns direct dependencies on the extensions it ships. `@namzu/files`\nis standalone. Nothing in the kernel depends back on any leaf package.\n\n| Package | What it is |\n|---|---|\n| `@namzu/sdk` | The kernel: run loop, tools, sessions, budgets, compaction, checkpoints, permission gate, connectors, telemetry |\n| `@namzu/cli` | The terminal agent, and the operator commands. Also importable as a library |\n| `@namzu/sandbox` | Sandbox providers beyond the in-kernel one |\n| `@namzu/telemetry` | The exporter pipeline, kept separate so consumers who emit nothing install nothing |\n| `@namzu/computer-use` | Screenshot, mouse and keyboard control through platform-native tools |\n| `@namzu/live` | Transport-agnostic live sessions orchestrating caller-supplied speech and audio-output drivers |\n| `@namzu/lsp` | Language-server-backed code navigation and symbol resolution |\n| `@namzu/files` | File registry contracts, with in-memory, local-disk, Azure Blob and HTTP backends. Pre-1.0 |\n| `@namzu/evals` | The kernel's own behaviour suites, runnable against an installed kernel |\n\nModel drivers, one per service. Direct SDK consumers install only what they\nuse; the CLI bundles the selected drivers named in its package README:\n\n| Package | Notes |\n|---|---|\n| `@namzu/anthropic` | Streaming, tool use, extended thinking |\n| `@namzu/openai` | Chat Completions, streaming, tool use |\n| `@namzu/deepseek` | Chat Completions, streaming, tool use, thinking mode |\n| `@namzu/bedrock` | Converse API, streaming, tool use |\n| `@namzu/openrouter` | Aggregated model access |\n| `@namzu/ollama` | Local models |\n| `@namzu/lmstudio` | Local models, GUI-managed |\n| `@namzu/http` | Zero-dependency driver for any compatible HTTP endpoint |\n\nEvery driver implements the same `LLMProvider` contract and registers itself\nthrough `ProviderRegistry`, extending the config union by module augmentation\nso `ProviderRegistry.create({ type: 'ollama', ... })` is fully type-narrowed.\nA mock driver ships in the kernel, pre-registered, and is scriptable turn by\nturn — including malformed and truncated tool calls — so you can test the loop\nwithout the network.\n\n## How this repository is kept honest\n\nTwo design rules run through the code, and you will meet both within an hour\nof reading it:\n\n- **Refuse, do not silently degrade.** A capability that is accepted and then\n  quietly not applied is worse than one that errors, because the caller stops\n  looking. A host that cannot supply a requested isolation control gets a\n  refusal, not a weaker sandbox; a driver that cannot honour a requested\n  capability must say so rather than drop the field.\n- **A declaration nothing drives is a defect.** A field no code reads and a\n  check that cannot fail are treated as bugs rather than as roadmap. Where a\n  thing genuinely is not built yet, the honest state is written down next to\n  it rather than implied away.\n\nAlongside those, the pull-request gate runs more than the usual four. Besides\nlint, typecheck, build and tests on two Node versions, every change also has\nto pass: a **public-surface baseline diff** (a symbol cannot vanish from the\npackage barrel unnoticed); **per-module coverage floors** plus a rule that\nevery source folder is explicitly classified for test presence; a\n**behaviour-regression eval suite**; **process-level tests** run in a real\nseparate process, because an in-process test cannot prove a run survives on\nits own event-loop footprint; a **consumer-install check** that catches\npeer-range drift before a publish rather than at the registry; package-manifest\nvalidation; and an audit that refuses a list of third-party product names in\nprose and identifiers, exempting the paths and the published vocabulary whose\njob is to speak somebody else's protocol — a driver package has to name the\nservice it drives, and a page telling an operator what namzu connects to has\nto name it too.\n\n## Next\n\n- [`docs/`](./docs/) — the knowledge bundle, an [OKF v0.2](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)\n  directory of concept pages that grows as the code they describe changes.\n  Read it here in the repository: there is no documentation site yet.\n- [`packages/sdk/README.md`](./packages/sdk/README.md) — the kernel's\n  subsystem map.\n- `AGENTS.md` — the working contract any coding agent in this repository\n  follows.\n\nSome pages under `docs/` predate recent kernel changes, and an audit of them is\npartly done rather than finished. Where a page and the code disagree, the code\nis correct; please open an issue.\n\n## Status\n\nReleases are driven by Changesets, so a package newly added on `main` can\nappear in this table before its first registry release. Two things a reader\nshould weigh honestly:\n\n- **Majors move quickly.** This project treats *any* backward-incompatible\n  change to a public API as a major, however small the diff — so the version\n  number tracks the surface rather than the size of the work, and it climbs\n  faster than you may expect. Pin your dependency and read the changelog.\n- **`@namzu/cli`, `@namzu/files`, `@namzu/evals`, `@namzu/live` and\n  `@namzu/lsp` are pre-1.0** and their APIs still move. The kernel itself is\n  the stable surface.\n\nNode 20 or newer is declared; CI exercises 22 and 24.\n\n## Contributing\n\nIssues and pull requests welcome at\n[cogitave/namzu](https://github.com/cogitave/namzu). See\n[`packages/sdk/CONTRIBUTING.md`](./packages/sdk/CONTRIBUTING.md).\n\n## License\n\n[FSL-1.1-MIT](./LICENSE.md) — every published version becomes MIT-licensed two\nyears after its release.\n",
  "bytes": 26595,
  "sha": "49b640ef8a361db8e26933e8e8fd4547e5e1ec8a473187d44f9843f55133c92d",
  "repo_slug": "cogitave/namzu",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/okf_cogitave_namzu_docs_index_md_99e082f8/readme"
}