Skip to content

About

funes memory tool integrations for agent harnesses

Resources

Stars

3 stars

Watchers

0 watching

Forks

Latest commit

 

History

115 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

funes-integrations

The agent integrations Hugging Face maintains for funes — claude, codex, hermes and pi — and the catalog funes add <id> installs them from. Integrations maintained by their authors live wherever their authors put them; COMMUNITY.md is where they are listed.

Layout

One directory per integration, each a bundle as funes's integration contract describes it: a manifest.json, a setup executable, whatever the integration needs beside them, and its own tests under test/. What each one installs into its agent, which of its events it hooks, and what it needs on the box is in its README; what they share is below.

hf-traces/ is the one directory that is not an integration. It converts Hugging Face agent-traces datasets, and installs nothing.

How the bundles automate

Each bundle gives its agent the funes read tools — funes mcp registered as an MCP server, or fronted by the extension where the agent has no MCP client — and drives one script of its own, funes-index.sh, in two modes. Per turn, it converts the session that just changed into funes's spool and runs funes index --harness <id>, then converts any other session changed since it last ran, so a session whose own hook never fired — untrusted, timed out, a host that died mid-turn — is caught at the next turn; the run is time-boxed, so a backlog fills in a bounded step per turn. At the session boundaries, as funes-index.sh --publish and only with a memory bound, it converts, indexes — waiting out a per-turn run's lock — and pushes; it runs at the session's end and again at the next start, catching up whatever a missed end left behind. The conversion is the bundle's own converter: a script for Claude Code and Codex, the extension or plugin itself for pi and Hermes. The work runs detached, so a hook returns in well under a second and never blocks the turn or trips a timeout. The memory rides in a file beside the scripts, so every hooks file is static.

Bundle Per turn Publish, with a memory bound
claude Stop, SubagentStop SessionEnd, SessionStart
codex Stop SessionEnd, SessionStart
hermes post_llm_call on_session_finalize, on_session_start
pi turn_end session_shutdown, and session_start when the process is fresh

At install, setup add converts the sessions the agent has already written. The claude and codex setups share a mark with their hooks' sweeps, so a re-add reads only the sessions written since the last of either, and leaves out each one whose last turn the local memory holds, as its funes sessions row says (funes 1.9.0 and newer). Both keep those rows beside their scripts: a session listed there and gone from the memory since has the whole history read again, and for claude, a session the memory holds without the messages typed while Claude was working keeps that numbering, and never gets them.

What funes guarantees around these — local-first indexing, one writer at a time, the secrets gate, the wrong-memory guard — is in funes's automation docs.

Converting by hand

Indexing an agent's history on a machine that never ran the automation — an archive, a colleague's export — is the bundle's converter into a directory of your own, then funes index on that directory, as funes's add docs describe. Each converter is its bundle's own, and emits the session and turn ids the hooks do. <bundle> is ~/.funes/agents/<id> once funes add <id> has run on any machine, or <id>/ in this checkout:

Bundle Converter
claude <bundle>/claude-plugin/funes/convert <transcript.jsonl> [out.funes.jsonl] — needs jq; one argument prints to stdout
codex <bundle>/codex-plugin/plugins/funes/convert <rollout.jsonl> [out.funes.jsonl] — needs jq; one argument prints to stdout
pi node <bundle>/convert.mjs <session.jsonl | sessions-root> <out-dir> — a root converts every session under it
hermes python3 <bundle>/plugin/convert.py <state.db> <out-dir> [session-id] — every session in the store unless one is named
for t in /archive/.claude/projects/*/*.jsonl; do
    ~/.funes/agents/claude/claude-plugin/funes/convert "$t" ~/imports/"$(basename "$t" .jsonl)".funes.jsonl
done
funes index ~/imports

Hugging Face agent-traces datasets

The Hub keeps a parquet copy of an agent-traces dataset on its refs/convert/parquet branch. hf-traces/convert.py turns it into one turns file per session. It needs pyarrow, which uv run installs from the script's own header:

hf download <org>/<repo> --repo-type dataset --revision refs/convert/parquet --local-dir traces
uv run hf-traces/convert.py traces ~/imports
funes index ~/imports

It maps a session as funes's own reader did when funes index <org>/<repo> read these datasets, so a dataset a memory already holds keeps its turn ids and a re-import adds nothing. A session id that is not a plain file name is reported and skipped.

Developing

A working copy installs into funes straight from the checkout:

funes add pi --from ./pi

funes confirms at the terminal before running files it did not publish — once, until they change. Each bundle's tests run without a funes binary, against fakes:

sh pi/test/run.sh

The hf-traces test needs pyarrow. PYTHON names the interpreter that has it:

PYTHON="uv run --with pyarrow python" sh hf-traces/test/run.sh

Releasing

A release is an integration's directory packed as <id>.tar.gz, published under <id>/<version>/ in the huggingface/funes-integrations bucket with a SHA256SUMS beside it, and listed in the bucket's catalog.json. Versions are the integration's own — version in its manifest, MAJOR.MINOR.PATCH — independent of funes's, and a published version is never replaced.

  1. Bump version in <id>/manifest.json and merge.
  2. Tag <id>-v<version> — pi-v1.0.1 — and push the tag, or run the Release workflow by hand with the id and version.

The workflow checks the manifest against the tag, runs the bundle's tests, packs and publishes the archive, and adds the release to the catalog. It needs HF_FUNES_INTEGRATIONS_RELEASE_TOKEN: a token that can write that bucket, and nothing else. Releases run one at a time, since the catalog is read, amended and written back.

The catalog

catalog.json, catalog_version 1:

{
  "catalog_version": 1,
  "integrations": {
    "pi": {
      "repo": "huggingface/funes-integrations",
      "releases": [
        {
          "version": "1.0.0",
          "contract_version": 1,
          "url": "hf://buckets/huggingface/funes-integrations/pi/1.0.0/pi.tar.gz",
          "sha256": "…"
        }
      ]
    }
  }
}

For the id it was asked for, funes takes the newest release whose contract_version is the one it speaks, fetches the archive at url with the SHA256SUMS beside it, and refuses it unless its digest is sha256 and its manifest declares version. Fields funes does not know are ignored.

About

funes memory tool integrations for agent harnesses

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages