Early AccessEvery agent is free to connect — no card, no checkout. Paid agents are coming.

Documentation menu
Building agents

Manifest spec

An agent manifest describes everything an agent is — its prompt, its tools, how it reaches a client, and what credentials it needs. A manifest only describes; it never ships executable code.

Core fields

Every manifest carries a small core: a name, an optional description, the system prompt, example prompts, and the tools the agent can use. A plain recipe needs only these; a tool-using (doer) agent adds the layer below that lets it actually do things — tool actions, credential slots, guardrails, delivery, and client targets. You rarely write a manifest by hand: the submit builder and the GitHub/manifest importer assemble and validate it for you.

FieldTypeNotes
namestring3–80 characters.
descriptionstring?Up to 4000 characters.
system_promptstringThe agent’s instruction set (50–20,000 characters).
toolsTool[]Up to 40 tools (see below).
example_promptsstring[]1–5 example prompts that show the agent in use.
compatibilityobject?Optional per-client version hints (Claude / ChatGPT / Gemini).
Category is a hint, not an exact match
category is a loose hint, not a required exact slug. FindAgent resolves it against its two-axis taxonomy — a primary discipline plus an optional industry, each with a subcategory — so a plain "finance" lands on the Finance & Accounting discipline rather than failing to match. Importers that can name the axes may send a taxonomy object instead. The full shape (kind, tools, credential slots, guardrails) is also auto-detected on import, so a tool-using manifest is brought in completely even when it doesn't spell out a schema version.

Listing metadata

Beyond the executable core, a manifest may carry the marketplace listing fields that decide how the agent is presented and found. All are optional — the submit builder lets you fill or edit any of them — but if you include them in the manifest, the importer reads them so you don't retype what you already wrote. Each also accepts a couple of common aliases, so a manifest exported from another tool imports cleanly.

FieldTypeAlso acceptsNotes
taglinestring?A one-line pitch shown on the card (up to 140 characters).
categorystring?category_slug · primary_categoryThe primary category hint (resolved to a discipline — see above).
additional_category_slugsstring[]?additional_categories · subcategoriesExtra category hints (e.g. an industry). Up to 8.
tagsstring[]?Free-form search tags. Up to 16.
llmsstring[]?Legacy client-target hint. You do NOT need to set this — a hosted agent connects to every MCP client over the gateway, so it defaults to the universal set. Kept for back-compat; unknown values are dropped.
industry / disciplinestring?taxonomyName the two axes explicitly instead of a single category hint.
versionstring?A self-described release version (semver, e.g. "1.0.0"). FindAgent tracks the authoritative version separately — this is descriptive metadata.
changelogstring?release_notesHuman release notes for this version (up to 10,000 characters).

A manifest may also carry a metadata object with the professional trust + support links buyers look for. All fields are optional, and every URL and the icon must be an https:// URL. When you submit, an invalid field rejects the submission so you can fix it; when a manifest is imported, an invalid metadata block is simply dropped from the prefill for you to re-enter.

metadata fieldTypeNotes
licensestring?A short license id, e.g. "MIT" (≤64 chars).
homepagestring?Project homepage. Must be an https:// URL (≤500 chars).
docs_urlstring?Documentation link. https:// only (≤500 chars).
support_urlstring?Support / issues link. https:// only (≤500 chars).
support_emailstring?A support email address.
iconstring?Listing icon URL. https:// only (≤500 chars).
author / maintainerobject?A { name, url? } credit. name is required (≤120 chars); url (optional) must be https://.
You never lose what you wrote
These listing fields aren't part of the validated execution manifest — the runtime never reads them, so the schema ignores any it doesn't recognize. They are prefill hints the importer reads and the submit builder re-validates: anything the manifest carries is filled in for you to confirm or change, and anything it omits you set in the builder. Nothing here is executable; these fields only describe the listing.

Tools

A tool is a named capability the agent can call. A tool carries an MCP-shaped name (1–64 chars, a-zA-Z0-9_-, unique within the manifest), a description (10–500 chars — a shorter one fails validation), an optional JSON-Schema input_schema / output_schema, an optional response_kind (text / json / binary), optional behaviour annotations, and an optional action binding that says what it does when called. A manifest carries up to 40 tools.

Annotations map directly onto how clients and runtimes gate a tool: readOnlyHint, destructiveHint, idempotentHint, and openWorldHint — plus the FindAgent framing hints interactiveHint and execution (client / app) that drive the interactive / app-only tool types. A source that marks a mutating action readOnlyHint: true is overridden — the security floor wins.

Actions

A tool's action is the only thing that does work, and it comes from a fixed, auditable set of binding kinds — never arbitrary code:

  • http — an HTTP request. Declares method (one of GET / POST / PUT / PATCH / DELETE), a url (which may contain {param} placeholders bound from the tool input), optional headers and body_template, and an optional auth_ref pointing at a credential slot.
  • prompt-template — a templated prompt the runtime fills and returns. A powerful pattern: have the step return a refusal token instead of an answer when its input is insufficient, so “don't answer without enough to go on” becomes a value the step can return rather than mere prompt advice. Useful tokens creators return: NO POLICY FOUND, INSUFFICIENT SOURCE, NO USER-FACING CHANGE, INSUFFICIENT CONTEXT. A downstream step (or the caller) can branch on the token instead of acting on a low-confidence answer.

Multi-agent orchestration (one agent calling another) is served by a Department, not a tool action.

Credential slots

When an action needs a secret, the manifest declares a credential slot and the action references it by auth_ref. Each slot has a ref, a human label, an optional env var name, and — importantly — allowed_hosts:

  • allowed_hosts binds the secret to an audience. The runtime only attaches the credential when the request's destination host matches (exact or subdomain).
  • A slot with no allowed host is refused — a credential without an audience is a cross-host exfiltration risk.
  • type describes the value shape so the install UI renders the right input: string (plain text, the default), secret (masked), or json (a JSON blob — e.g. a service-account key file). A json key that must be signed into a token (a Google/GCP service-account JWT) only works for a code-bundle or hosted agent whose code can perform the signing — a pure declarative http doer can attach a credential but cannot sign a JWT, so reach for code-bundle when the API needs signed short-lived tokens. This also changes which hosts you must allow: a plain type: secret API key on a Google API (e.g. a Gemini key hitting generativelanguage.googleapis.com) reaches the data host directly, so that one host is enough. A type: json service-account key first exchanges its signed JWT for a short-lived token at oauth2.googleapis.com before the data call, so it must allow the Google auth hosts (oauth2.googleapis.com, www.googleapis.com, accounts.google.com) alongside the data host — miss the token host and the call is blocked by the egress guard before it starts.
  • description is optional buyer-facing help text shown above the field at install time (e.g. “Paste your GA4 service-account JSON key”). It never holds a secret.
  • required marks whether the buyer must supply the slot. Defaults to true; set it false for a credential the agent degrades without.
  • auth_scheme selects how the secret is attached to the request: bearer (default — Authorization: Bearer <token>, what GitHub and most modern APIs expect), basic (Authorization: Basic <base64(id:token)> — Atlassian / Jira / Confluence and other API-token services; the buyer supplies the base64, the runtime never re-encodes it), raw (the Authorization value verbatim, e.g. token <x> / ApiKey <x>), or header (a CUSTOM header instead of Authorization — set header_name, e.g. X-API-KEY for Metabase or X-Figma-Token for Figma, with an optional prefix the runtime prepends). A Bearer token sent to a Basic-auth API is rejected, so declare the scheme the target expects.
  • install_host — set true for a self-hosted target whose host isn't known until install (a company's own GitLab, Jira Server, Airflow, or Metabase). Leave allowed_hosts empty for that slot: the buyer types their host at install and it becomes the slot's audience. A tool's url can reference it as {install_host} (e.g. https://{install_host}/api/v4/projects). The secret is only ever sent to the host the buyer entered — nothing widens the audience. Add an optional host_example (e.g. gitlab.mycorp.com) to hint the placeholder. This works for a code-bundle agent too (e.g. a self-hosted Trivy or on-prem endpoint): the buyer's host is threaded into that run's sandbox egress and the secret is bound to it, so a code agent can also target infrastructure only the buyer knows the address of.
  • auth_acquisition — how the buyer gets the secret: paste (the default — the buyer pastes a key or token at install) or oauth (the buyer connects a provider once from their dashboard and the runtime resolves the acquired access token for this slot). For oauth you also set provider (e.g. github) — a provider id that must match FindAgent's integrations registry. An OAuth slot leaves allowed_hosts empty and does not use install_host: the token's audience is the provider's own API host(s), fixed server-side from the registry, so a single connection can be reused across agents without ever reaching a host the provider doesn't own. The provider must be enabled on FindAgent for the connect option to appear (GitHub is the first live provider).
What the buyer pastes depends on the scheme
The install screen shows a per-scheme format hint so a buyer enters the value the runtime expects. A bearer slot takes the raw token as-is. A basic slot takes the Base64 of id:token (e.g. email and API token joined by a colon) — pasting the raw token here is the most common “failed to parse auth token” mistake with Atlassian / Jira. A header slot takes just the key value (any prefix you declared is added automatically), and a raw slot takes the whole authorization value including the scheme word (e.g. token ghp_…). The same hint appears in the in-chat setup panel and in the CLI, so you don't have to explain it in your description. An auth_acquisition: "oauth" slot skips pasting entirely — the buyer clicks Connect once and there is no value to enter.

Guardrails

A doer agent can declare guardrails the platform enforces. The manifest only declares the rails — the FindAgent gateway, not the agent's own code, enforces them, the same way allowed_hosts and credential slots are declared in the manifest but policed by the runtime. A creator may only tighten the rails; mandatory ones can never be disabled.

  • input — applied before a call reaches the agent. max_length caps the payload size, deny_patterns is a prompt-injection deny-list, and pii_redaction redacts categories (credit_card, email, phone, iban, national_id, and more) from the payload.
  • output — applied after the agent returns. secret_leak_scan is mandatory: the platform always runs it (on the raw result), and a manifest that tries to set it false fails validation. Optional: pii_redaction strips the same PII categories from the RESULT before the caller sees it (e.g. a doer that pulls customer data into a Slack digest), and schema validates the result shape.
  • actions — a per-tool policy keyed by tool name. approval gates a write: none (default), human (the client must confirm before the action runs; where a client can't prompt, the call proceeds), or human_strict (same confirm, but if the client can't prompt the call is BLOCKED — fail-closed, for irreversible or high-value actions). max_amount is a spend cap compared against a top-level numeric argument under one of amount / amount_cents / total / value (in whatever unit your tool accepts — declare the cap in the same unit). It is a convention-based guard, not a semantic analyzer: an amount under a different key, nested, or sent as a string is NOT covered. rate_limit (e.g. 10/hour) and idempotent (whether the gateway may safely auto-retry the action after a crash) round it out.
  • requires — an ORDER rail: a list of tool names that must have run recently before this tool may run (e.g. create_issue: { requires: ["search_issues"] } — “always search before you create”). Enforced as a real gate, not prompt advice: the required tool must have been called by the same user within a 30-minute window or the call is blocked; on pass, your recent searches are shown back to you so you can re-search if none fits.

Delivery, kind, exec, and targets

FieldValuesWhat it means
kindstatic-recipe · mcp-tool · autonomous-agent · skills-bundle · code-bundleThe shape of the agent. Defaults to static-recipe.
deliveryprompt · mcp.stdio · mcp.remoteHow a client reaches the agent — as a paste-in recipe, a local stdio MCP server, or a hosted remote MCP URL.
execuser-local · findagent-hostedWhere it runs. Defaults to user-local.
targetsclaude-desktop · claude-code · chatgpt · cursor · vscode · gemini-cli · windsurf · cli · webWhich clients the agent is meant for.
authnone · api-key · oauth-deviceFindAgent identity auth, distinct from per-agent external credentials.

autonomous-agent is a reserved roadmap kind with no distinct runtime behavior yet — a submission using it is treated as an mcp-tool doer.

A listing-only MCP server — a server someone already runs, shown in the MCP directory — is a separate catalogue shape, not a manifest kind enum value: the listing points at an external server rather than describing an agent FindAgent runs. The directory shows each listing's connection so you can filter by it: Hosted (a remote MCP URL you add as a connector) or Local (a command you run on your own machine — FindAgent never runs it). A doer agent, whose tools carry real action bindings FindAgent's runtime executes, is the opposite of a listing and is never shown as one.

code-bundle runs in a sandbox
The code-bundle kind (see the code-bundle section below) runs a creator's real code inside an isolated, ephemeral sandbox FindAgent provisions for each run — never on your own machine, and walled off from FindAgent's own app and data. Code agents are scanned and reviewed before they publish, and connecting over the hosted gateway is the way you use them. See Code agents and the security model.

Skills-bundle agents

A kind: "skills-bundle" manifest packages a whole skills-or-rules repository — Claude Agent Skills, Cursor / Windsurf / Continue rules, an AGENTS.md, and similar — as a single agent. Each skill is declarative content (a Markdown SKILL.md), so the runtime serves it as an MCP prompt rather than executing it. The bundle adds:

  • skills_source — an R2 reference (kind: "r2" + key) to the imported skill files the CLI downloads and the runtime serves.
  • skills — the per-skill discovery metadata (id, name, description, tags) synthesized from each skill's frontmatter.
  • router_skill_id — optional id of the entry/router skill the runtime can surface first.

Because skill bodies are never executed, a skills bundle adds no code-execution surface — the same declarative keystone as a doer agent. Importing an arbitrary public repository is an admin-only seeding path; creators bring their own repo through the GitHub- connected submit flow.

Code-bundle agents

A separate manifest shape covers agents whose behaviour is real creator code rather than declared tool bindings. A code-bundle manifest sets kind: "code-bundle" and adds — entrypoint, runtime, and mcp are required; the rest are optional:

  • entrypoint (required) — the handler the runtime invokes: a bundle-relative path (e.g. src/agent.ts) and the export name to call (defaults to handler).
  • runtime (required) — the execution runtime: a kind (node or python) and an optional version hint the sandbox resolves to a concrete image.
  • mcp (required) — how the bundle is exposed over MCP: mode: "wrap" (the runtime auto-generates an MCP server around the entrypoint) or mode: "native" (the bundle ships its own MCP server, declaring the command + args that start it).
  • allowed_hosts — the default-deny egress allowlist; the only hosts the sandbox network policy lets the bundle reach.
  • build_command / install_cwd — an optional custom build step and the working directory to install + build from (for a bundle whose package root isn't the repo root).
  • ui — an optional static frontend (a bundle-relative path) served later inside a sandboxed iframe; absent means no UI.
  • env — a declared non-secret env contract (UPPER_SNAKE names + descriptions). Secrets never go here; they flow through audience-bound credential_slots, the same slot type a doer agent uses.

A code-bundle manifest reuses the same credential_slots, guardrails, and skills shapes. The security keystone is unchanged: the manifest only describes a bundle — storing, scanning, and sandboxed execution of the referenced code are platform responsibilities, and the bundle runs only inside the isolated sandbox, never on your machine during a normal install.

Example

A small doer agent with one HTTP tool and a host-bound credential slot:

findagent.json
{
  "name": "GA Report Builder",
  "description": "Pulls a traffic summary and writes it to a sheet.",
  "tagline": "Weekly traffic summaries, straight to your sheet.",
  "version": "1.2.0",
  "changelog": "Add a weekly-digest tool and fix the date-range parser.",
  "system_prompt": "You are a focused analytics assistant ...",
  "kind": "mcp-tool",
  "category": "analytics",
  "additional_category_slugs": ["marketing"],
  "tags": ["ga4", "reporting", "analytics"],
  "metadata": {
    "license": "MIT",
    "homepage": "https://example.com/ga-report-builder",
    "docs_url": "https://example.com/docs",
    "support_email": "support@example.com",
    "author": { "name": "Jane Doe", "url": "https://example.com" }
  },
  "tools": [
    {
      "name": "get_traffic_summary",
      "description": "Fetch a traffic summary for a date range.",
      "input_schema": { "type": "object", "properties": { "range": { "type": "string" } } },
      "annotations": { "readOnlyHint": true },
      "action": {
        "type": "http",
        "method": "GET",
        "url": "https://api.example.com/v1/traffic?range={range}",
        "auth_ref": "analytics_token"
      }
    }
  ],
  "credential_slots": [
    {
      "ref": "analytics_token",
      "label": "Analytics API token",
      "env": "ANALYTICS_TOKEN",
      "allowed_hosts": ["api.example.com"]
    }
  ],
  "example_prompts": ["Summarize last week's traffic."],
  "delivery": { "mcp": { "stdio": { "command": "findagent-mcp", "args": ["run", "ga-report-builder"] } } },
  "exec": "user-local",
  "targets": ["claude-desktop", "cursor", "cli"]
}