Agent Manifest Documentation

Consuming a manifest

This page is for someone building software that could read an Agent Manifest. It goes from not knowing what this is to one decision in your program taking a different branch because a declaration said so — nothing further.

It asks you to publish nothing, adopt no tooling of ours beyond a reading library, and copy no schema.

What a manifest is

An Agent Manifest is a JSON document in which the operator of an autonomous system declares, before any interaction, what that system is for, what it will not do, how much autonomy it has, who can stop it and what it records. The normative definition is the specification and its JSON Schema.

It is a declaration, not a credential. It is not signed and proves nothing about who issued it. That single fact decides how it can be used, and the last section of this page says how.

Install the reading client

npm install @agent-manifest/client

Node.js 22.12 or later. The package reads, canonicalises, fingerprints, compares and structurally validates declarations. It ships no thresholds, no profiles and no recommended lists, and it emits no verdict about trust, safety or compliance.

Read one

Resolving by name takes two calls: a registry has to be discovered before a name can be looked up in it.

import { discoverRegistry, resolve } from '@agent-manifest/client/net';

const registry = await discoverRegistry('agent-manifest-spec.org');
const result = await resolve('the-diplomat', { registryUrl: registry.registryUrl });
const manifest = result.resolutions[0].document;

console.log(manifest.autonomy.level, manifest.forbidden_actions);

A URL resolves in one call. Passing a bare name with no registry returns a result whose absence.reason is no-registry-declared — the client reports what it could not conclude instead of guessing.

That reporting is why resolutions can be empty, and the line above takes resolutions[0] without checking. A name the registry does not list resolves to nothing, absence.reason is not-in-registry-index, and resolutions[0] is undefined. Check the length, or read absence, before reaching for a document: absence is an answer here, not an error.

Read one from disk

import { readFileSync } from 'node:fs';
import { parse } from '@agent-manifest/client';
import { validate } from '@agent-manifest/client/validate';

const { document } = parse(readFileSync('manifest.json', 'utf8'));
const { schemaValid, errors } = validate(document);

parse() returns { document, form }, not the document. form records whether it was read from text or from an already-parsed value. Passing the wrapper straight into validate() reports every required field as missing, which looks like a broken manifest and is not one — destructure it.

Change one decision

Four worked examples, one file each, in the client repository: examples/.

Example The decision, which you are already making today Field A B
CI gate a run passes or fails autonomy.level exit 0 exit 1
Gateway a call is forwarded or refused forbidden_actions 403, upstream never touched 200, upstream reached
MCP server which tools are advertised and which run forbidden_actions 1 advertised, call refused 2 advertised, call runs
Runtime which isolation a job is launched under risk_profile.level disk read allowed ERR_ACCESS_DENIED

Each one runs two inputs through the same code and produces two observable behaviours. That pair is the whole point: reading a manifest and printing it is not consuming it.

The MCP example is an explicit derivation of the gateway one rather than a case of its own, and says so in the file. The case that would be native to an MCP server — using a manifest to establish who is calling — is precisely the one a manifest cannot support.

The policy is yours

In all four examples the threshold sits in the example, marked to be edited. Nothing in the package decides what an acceptable autonomy.level is, and nothing will. The declaration layer stops at the declaration; the policy seat is left deliberately empty because it belongs to whoever is running the software.

The mapping between an action your software knows about and a string a manifest declares is part of that policy too: v1.0 defines neither a vocabulary nor a matching rule. See Known limits of v1.0.

Restrict, do not grant

Use what is declared to take away: refuse a run, block a call, narrow a tool list, confine a process.

A manifest carries no signature, so in the granting direction — deciding who a caller is, handing out a privilege, extending trust — a lie pays off and nothing stops it. In the restrictive direction the missing signature stops mattering: a false declaration can only be turned into a shorter leash for the declarer.

This is why nothing here authenticates an agent, treats a manifest as a credential, applies enforcement on anyone’s behalf, or issues badges, seals or certifications.

What is not being asked of you

Publishing your own manifest, adopting the CLI, the registration flow or any other tool of ours, copying the schema into your repository, or mentioning this project anywhere.