Skip to content

@ahpd/agent-cofold ​

npmCIlicense MITnode >=22Agent Host Protocol 0.9.0

The cofold agent runtime as a backend for @ahpd/sdk, and a plugin for the @ahpd/server daemon. It registers the provider cofold, and every model an OpenAI-compatible endpoint serves is a model inside it.

A session uses the models and keys cofold already knows about, and runs cofold's file, shell, web and memory tools in the daemon's process.

Part of ahpd. The source is in packages/agent-cofold.

Install ​

bash
ahpd plugin install @ahpd/agent-cofold
ahpd restart

Update, remove and one-run flags such as --plugin are in Plugins.

Options ​

In the configuration file, with the backend's own options as defaults for every session it serves:

json
{
  "plugins": [
    {
      "name": "@ahpd/agent-cofold",
      "options": {
        "model": "deepseek-chat",
        "baseUrl": "https://api.deepseek.com/v1",
        "apiKey": { "$secret": "host:deepseek" },
        "store": "/var/lib/ahpd/cofold",
        "tools": { "web": { "search": { "duckduckgo": true } } }
      }
    }
  ]
}

With no model named anywhere, the providers, keys and model come from cofold's own configuration file, $COFOLD_CONFIG or $XDG_CONFIG_HOME/cofold/config.json or ~/.config/cofold/config.json. Inside a machine the first of those is what finds it.

Every option below is a key under options in the plugin's entry, and the daemon checks each value against the schema before apply runs.

OptionDefaultWhat it does
providercofoldThe id a client names in createSession
displayNameCofoldWhat a person reads instead of the id
descriptionnoneOne line about this backend
modelthe cofold file'sThe model id a session that names none runs on
baseUrlthe cofold file'sThe OpenAI-compatible endpoint a session that names none uses
instructionsthe cofold file's, else You are a helpful assistant.The system prompt the agent is created with
computerConfigDir/ahpd/cofoldThe configuration directory the harness reads inside a machine: a state volume seeded with its config.json, or that file mounted read-only in a profile with state: "host". false leaves the image's own
store$XDG_DATA_HOME/ahpd/cofoldWhere the cofold file store lives
memoryfalsetrue to hold the store in memory, for a test
toolsall four onWhich capabilities a session runs, and where web_search gets its providers
strictToolstruefalse holds tools to the loose check, so a key cofold does not know is dropped rather than refused
apiKeythe cofold file'sThe daemon's own key. { "$secret": "host:<name>" } reads it from the vault; an embedder may pass a function asked once per request
resourcethe endpoint's origin when it is httpsThe protected resource a client authenticates against
adapterthe HTTP oneA cofold ModelAdapter used instead of the HTTP one, for an embedder or a test
autoCompactTokens80% of the model's listed context, or of 32000The estimated history size at which a session compacts, never above that 80%
policycofold's own defaultThe run-level policy a pause comes from, which turns the approvals mode control off

ahpd vault set host:<name> keeps a key that apiKey or a search provider's apiKey reads with { "$secret": "host:<name>" }, from standard input. See PLUGINS.md for a $secret.

tools ​

An absent key is on, and false turns that capability off.

OptionDefaultWhat it does
filestrueread_file, write_file and edit_file, titled by the file; list_files and search_files, titled by the pattern
shelltrueshell_exec, titled by its command, one command at a time through the platform's shell
memorytruememory_read and memory_write, titled by the memory file, under <store>/memory/<workspace slug>/
webtrueweb_fetch, titled by the URL; an object adds web_search, titled by the query, over the providers in its search

The providers web_search asks, in the order they are written. A failing one is skipped.

OptionDefaultWhat it does
bravenoneBrave Search, as { "apiKey": "..." }
tavilynoneTavily, as { "apiKey": "..." }
duckduckgofalsetrue scrapes DuckDuckGo's results page, with no key

In your own host ​

bash
pnpm add @ahpd/agent-cofold @ahpd/sdk
ts
import { createHost, listen } from '@ahpd/sdk';
import { cofoldAgent } from '@ahpd/agent-cofold';

const host = createHost({
  path: process.cwd(),
  agents: [cofoldAgent({ model: 'deepseek-chat', baseUrl: 'https://api.deepseek.com/v1' })],
});
await listen({ port: 9187 }, (peer) => host.accept(peer));

In a machine ​

A session in a machine runs nested: an ahpd from the ahpd part, which carries this plugin, is started inside, so any glibc image runs it with nothing installed. Its configuration is a state volume at /ahpd/cofold, seeded with this host's file, and the keys in that file are readable by anything in the machine. See Cofold in a machine.

The tools a session runs ​

A session gets @cofold/tools' four capabilities by default, so it can read, search, edit and write files, run one command, fetch a page and search the web when a provider is configured, and keep memory. The permission mode is what confines them rather than the workspace, and default asks before a write, a command, a web fetch and a read outside the workspace. A session that names no mode gets auto, where a read, inside or outside, and a web fetch run and only a write or a command asks. An approval offers Allow once, Allow the tool for this session, and Deny; the session choice is sent as alwaysApprove, and cofold does not ask about that tool again in the session.

The workspace check resolves symlinks with cofold's own resolver, including a link whose target does not exist yet, so a write through a link that leaves the workspace is outside it. web_fetch refuses loopback, private and link-local addresses on every hop, though not the machine's public address, and a name that answers with a different address at the connection is not caught.

A write or an edit needs the file to have been read in this session, and cofold refuses one it has not seen. A file that changed since it was read is refused too. What a session read is held in the process, so a restart means reading it again. "files": { "requireRead": false } turns the rule off for the session, and the rule stays on when the key is absent.

Memory is per workspace and shared by the sessions in it, under <store>/memory/<workspace slug>/. A session opened with no working directory keeps its tools and works in the daemon's current directory. A shell call is drawn as a terminal with its bare command, and a turn with no model configured fails with a sentence that says to add "model" to the cofold configuration file.

tools turns one off by naming it false, and gives web_search its providers:

json
{ "tools": { "shell": false, "web": { "search": { "duckduckgo": true } } } }

The named providers are tried in the order the configuration lists them, and a failing one is skipped.

Documentation ​

PLUGINS.mdThe whole backend, the session settings and the cofold configuration
AGENT.mdThe Agent and Session contracts this implements
cofoldThe agent runtime this runs

License ​

MIT © Softov