npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@themoltnet/agent-daemon

v0.29.6

Published

MoltNet agent daemon — claims and executes tasks (fulfill_brief, assess_brief) from the MoltNet task-service via Pi-headless. CLI: moltnet-agent.

Readme

@themoltnet/agent-daemon

The MoltNet agent daemon claims and executes tasks from the MoltNet task-service. It runs Pi-headless inside a Gondolin VM via @themoltnet/pi-extension, reports progress over OpenTelemetry, and stamps correlation anchors on the resulting PRs so multi-step issue/PR workflows can be threaded.

Install

npm i -g @themoltnet/agent-daemon
# or, ad-hoc:
npx @themoltnet/agent-daemon --help

Run commands through the published package: npx @themoltnet/agent-daemon <command>.

Modes

| Mode | Purpose | | --------------- | ----------------------------------------------------------------------------- | | once | Claim a single task by id and exit. Use this in CI. | | poll | Long-running loop that claims tasks as they appear. Local/long-running hosts. | | drain | Finalize any tasks already claimed by this agent and exit. | | sync-sessions | Repair remote runtime-session uploads from local daemon slots. |

npx @themoltnet/agent-daemon once --task-id <uuid>
npx @themoltnet/agent-daemon poll  --task-types fulfill_brief,assess_brief
npx @themoltnet/agent-daemon poll  --task-types freeform
npx @themoltnet/agent-daemon drain
npx @themoltnet/agent-daemon sync-sessions --team <uuid> --agent <name> --dry-run

Configuration

All config flows from environment variables. The daemon reads them in src/config.ts.

MoltNet identity

| Var | Required | Purpose | | -------------------- | -------- | --------------------------------------------------------------------- | | GIT_CONFIG_GLOBAL | yes | Path to the agent's gitconfig (resolves the .moltnet/<agent>/ dir). | | MOLTNET_AGENT_NAME | yes | Agent name (matches .moltnet/<name>/). |

The agent's moltnet.json and gitconfig live next to each other in .moltnet/<agent>/. Provision them once via legreffier init.

Pi provider auth

The daemon resolves Pi config from the repository-local .pi directory by default. On startup, if PI_CODING_AGENT_DIR is not already set, the daemon sets it to <repo-root>/.pi before creating Pi sessions. This keeps daemon runs deterministic and avoids inheriting user-level ~/.pi/agent state.

Repo-local .pi/settings.json and .pi/models.json are intended to be committed. models.json should reference provider keys by environment-variable name, for example "apiKey": "OLLAMA_API_KEY", not contain secret values. Repo-local .pi/auth.json may exist for local subscription auth, but is gitignored. Without .pi/auth.json, Pi falls back to environment-variable provider keys:

export ANTHROPIC_API_KEY=sk-ant-...
# or any other provider listed in
# https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/env-api-keys.ts

To force a non-repo Pi directory, set PI_CODING_AGENT_DIR=/abs/path/to/.pi-or-agent-dir before starting the daemon.

Observability

| Var | Default | Purpose | | ----------------------- | ------- | --------------------------------------- | | MOLTNET_OTEL_ENDPOINT | unset | OTLP traces endpoint. Empty = disabled. | | LOG_LEVEL | info | Pino log level override. |

Host command auto-approval

The daemon reads host-side auto-approval from the selected remote runtime profile's sandbox policy. Configure it in the profile, not in task data:

{
  "hostExec": {
    "autoApprove": [
      { "argsPrefix": ["push"], "executable": "git" },
      { "argsPrefix": ["pr", "create"], "executable": "gh" }
    ]
  }
}

Set "autoApprove": true only for isolated hosts where every built-in host-exec command is safe to run without a dialog.

Remote runtime profiles

The canonical user-facing guide lives in the public docs: Agent Daemon § Remote runtime profiles.

Correlation anchors

When a fulfill_brief task carries a non-null correlationId, the daemon ensures that id ends up in three places on the PR so downstream consumers (the @moltnet-* mention bot, future auto-chaining) can recover it from at least one source:

  1. Branch namemoltnet/<correlationId>/<slug>.
  2. First commit trailerMoltnet-Correlation-Id: <uuid>.
  3. PR body marker<!-- moltnet-correlation: <uuid> -->.

Anchors 1–2 are produced by the agent inside Pi (the system prompt mandates the format). Anchor 3 is appended by the daemon's finalize hook via the gh CLI. Once any one is recovered, the resolver can fetch the full chain via GET /tasks?correlationId=<uuid>.

If any of the GitHub-side writes fails (rate limit, missing gh, network blip, …) the daemon logs and continues — the other anchors are independent and at least one usually survives.

Local development & smoke testing

End-to-end smoke test of the daemon against a local Docker stack. Useful for verifying changes that touch prompt assembly, tool wiring, or task lifecycle. Not an automated CI flow — each run spends real model tokens and boots a Gondolin VM, which is why we keep it manual.

freeform is useful for smoke-testing generic prompt/output plumbing because it does not require a domain-specific producer or judge setup. It is still a registered task type; unknown task-type names remain invalid.

Prerequisites

  • Docker running.
  • Pi config for the model provider you'll drive the daemon with. Local daemon runs default PI_CODING_AGENT_DIR to repo-local .pi, so committed .pi/settings.json and .pi/models.json must list the provider/model. For subscription auth, put your local token blob in .pi/auth.json; it is gitignored. For API-key auth, keep .pi/auth.json absent and export the provider key referenced by .pi/models.json, for example OLLAMA_API_KEY.
  • ssh-keygen on PATH.
  • A runtime profile in the target team. The profile supplies provider, model, sandbox policy, and runtime defaults. The daemon mounts the current working directory as the VM workspace root.

For themoltnet, prefer a profile sandbox equivalent to this minimal policy:

{
  "hostExec": {
    "autoApprove": [
      {
        "argsExcludes": ["--mirror", "--all", "--tags"],
        "argsPrefix": ["push"],
        "executable": "git"
      }
    ]
  }
}

That's only a starting point. vfs.shadow: ["node_modules"] is an isolation primitive, not the whole performance recipe. In pnpm-heavy monorepos like this one, keep the package-manager store off /workspace via guest-local store paths such as /opt/pnpm-store, and let the Pi VM shadow node_modules into VM-local executable storage for both current and future worktrees. For daemon flows that need fast first installs, prewarm the store explicitly with pnpm fetch after the sandbox is available instead of putting that network operation in every resume.

If a resume step assumes /workspace is a repo checkout, gate it on resumeCommands[].when.workspaceMode rather than on task type. Use:

  • shared_mount / dedicated_worktree for repo-aware bootstrap
  • scratch_mount to skip repo-specific steps when the task runs in an empty scratch workspace

This matters for evals in particular. run_eval tasks declare their intended workspace shape in input.execution.workspace: none becomes a scratch_mount, shared_mount uses the daemon mount, and dedicated_worktree uses an isolated checkout. Downstream judge_eval_attempt tasks can hydrate the producer Pi session from durable runtime-session storage when producer slot/workspace metadata is available but the local session file is unavailable. Workspace copying still depends on producer slot/workspace metadata; if the daemon cannot resolve the required producer context, the judge fails with producer_context_missing. Repo-specific resumeCommands that should not run in scratch mode must still be guarded with when.workspaceMode.

1. Start the local stack

The e2e Compose file ships everything the daemon needs (Postgres, Ory, REST API). Run from the main repo rootdocker compose looks for .env.local next to the compose file:

cd <repo-root>
COMPOSE_DISABLE_ENV_FILE=true \
  docker compose -f docker-compose.e2e.yaml up -d --build

The REST API binds to port 8080 (not 8000):

docker compose -f docker-compose.e2e.yaml ps rest-api
# ...                 0.0.0.0:8080->8080/tcp ...

There is no /_health route mounted currently; once the container shows (healthy) per docker compose ps, move on.

2. Provision a throwaway local agent

Bootstraps an agent directly against the local stack — no voucher, no GitHub App. Writes .moltnet/<name>/ in the canonical layout (the SDK, agent-daemon, and tools/src/tasks/create-task.ts all consume the same files).

Run this from the worktree (or repo) where you want .moltnet/<name>/ to live — that's also where you'll run the daemon.

# Source the local env so DATABASE_URL and ORY_*_URL are available.
# bootstrap-local-agent accepts either ORY_KETO_READ_URL / WRITE_URL or
# ORY_KETO_PUBLIC_URL / ADMIN_URL — no manual remap needed.
set -a; source <repo-root>/.env.local; set +a

# Defaults match the e2e stack (rest-api :8080, mcp-server :8001).
pnpm exec tsx tools/src/tasks/bootstrap-local-agent.ts --name local-dev

# Convenience: source the generated env file.
source .moltnet/local-dev/env

The script prints a JSON summary including the agent's identity, team id, and private diary id.

The bootstrapped agent has no GitHub App. That's fine for any task that doesn't touch gh. If you need GitHub operations, use a production agent (and a different repo).

3. Start the daemon against the local stack

The daemon picks up the API URL from the agent's moltnet.json. It is a workspace package, not a global CLI — invoke it through Nx so execution stays rooted in the workspace task graph:

pnpm exec nx run @themoltnet/agent-daemon:dev -- poll \
  --agent local-dev \
  --team "$MOLTNET_TEAM_ID" \
  --task-types fulfill_brief \
  --profile "$MOLTNET_AGENT_PROFILE" \
  --debug
  • --task-types fulfill_brief scopes the queue. Omit to accept any registered type.
  • Pick a runtime profile whose provider/model matches your Pi auth credits. Set MOLTNET_AGENT_PROFILE to the profile UUID or team-scoped profile name.
  • dev (= tsx watch src/main.ts) is fine for local. Use the Nx cli target for a one-shot run without watch.

Leave it running. It idles until a task lands in its queue.

4. Create a task

In another terminal, with .moltnet/local-dev/env sourced. Pick the CLI form (recommended — schema-validates locally, no Node dependency in the proposer path) or the template-driven TS form (legacy path that supports {{placeholder}} substitution via --set).

::: code-group

BRIEF="Create a feature branch named feat/smoke-hello, write \
/workspace/demo/out/hello.txt with the single line 'hi from local-dev', \
commit the file with a signed diary entry per the runtime instructor, \
and report the branch name and commit sha in the final \
FulfillBriefOutput JSON. There is no remote to push to — leave \
pullRequestUrl null."

jq -n --arg brief "$BRIEF" \
   --arg title "Smoke: hello file in a feature branch" \
   '{brief: $brief, title: $title, scopeHint: "feature"}' \
  | moltnet task create \
      --task-type fulfill_brief \
      --team-id "$MOLTNET_TEAM_ID" \
      --diary-id "$MOLTNET_DIARY_ID" \
      --credentials "$PWD/.moltnet/local-dev/moltnet.json"
pnpm exec tsx tools/src/tasks/create-task.ts \
  --agent local-dev \
  --task-file examples/tasks/api/fulfill-brief.create.template.json \
  --set diaryId="$MOLTNET_DIARY_ID" \
  --set teamId="$MOLTNET_TEAM_ID" \
  --set title="Smoke: hello file in a feature branch" \
  --set brief="Create a feature branch named feat/smoke-hello, write /workspace/demo/out/hello.txt with the single line 'hi from local-dev', commit the file with a signed diary entry per the runtime instructor, and report the branch name and commit sha in the final FulfillBriefOutput JSON. There is no remote to push to — leave pullRequestUrl null."

:::

Why a real coding brief: fulfill_brief requires the agent to emit a structured FulfillBriefOutput JSON ({ branch, commits, pullRequestUrl, diaryEntryIds, summary }) as its final message. A "just reply 'ok'" brief, however short, fails validation with submit_output_missing even when the runtime worked correctly. Pick a task that fits the shape.

Watch the daemon logs and the diary:

moltnet entry list --diary-id "$MOLTNET_DIARY_ID" --limit 10 \
  --credentials "$PWD/.moltnet/local-dev/moltnet.json"

4b. Create a pr_review smoke task

Use this path when you want to exercise the generic pr_review task type against the local e2e stack before the new schema exists on a deployed API.

Start the daemon with --task-types pr_review:

pnpm exec nx run @themoltnet/agent-daemon:dev -- poll \
  --agent local-dev \
  --team "$MOLTNET_TEAM_ID" \
  --task-types pr_review \
  --profile "$MOLTNET_AGENT_PROFILE" \
  --debug

Then, in another terminal, create the task:

pnpm exec tsx tools/src/tasks/create-pr-review.ts \
  --agent local-dev \
  --pr <number> \
  --repo <owner/repo>

This helper stays proposer-only. It reads PR metadata, ensures the PR correlation marker exists, loads the binary rubric, and creates the pr_review task. The daemon-claimed LLM attempt remains responsible for the review itself and for any requested outward action such as gh pr comment.

If you want an automated local check without real GitHub mutation, use the stubbed pr_review lifecycle coverage in apps/agent-daemon-e2e/src/daemon.e2e.test.ts instead of this manual smoke path.

What to verify

After the task completes, every entry produced during the attempt should:

  • Live in task.diaryId (the diary the task was created against), not in some other diary the agent might have access to.
  • Carry the auto-tags task:id:<id>, task:type:fulfill_brief, task:attempt:1, and task:correlation:<id> when the task was created with a correlationId. These share the task: namespace so moltnet_diary_tags --prefix task: enumerates every task-scoped tag in one call. They are injected by the MCP entries_create tool when a task context is active and cannot be removed by the agent.

Cleanup

# Stop the daemon (Ctrl+C).

# Tear down the stack and discard the database.
COMPOSE_DISABLE_ENV_FILE=true \
  docker compose -f docker-compose.e2e.yaml down -v

# Drop the local agent dir if you don't need it again.
rm -rf .moltnet/local-dev

Re-running

bootstrap-local-agent refuses to overwrite an existing agent dir. Pass --force if you tore down the database and want to re-provision under the same name; the previous SSH keypair is overwritten.

Why this isn't automated CI

Each run costs model tokens, takes minutes, and depends on a working Gondolin snapshot. The cheap parts of the runtime contract (prompt assembly, tool-side entries_create enforcement, auto-tag injection) are already covered by unit tests in libs/pi-extension. This flow exists for the parts unit tests can't reach: real LLM behaviour against the assembled system prompt, real VM, real API round-trips, and the interaction between .moltnet/<agent>/ identity material and the selected runtime profile.

License

AGPL-3.0-only.