Hosted onhoraciohdev.dev.hyper.mediavia theHypermedia Protocol

Plan — Knowledge Manager Agent on oc.hyper.mediathe Claude Code plan for our agent

Context

Deploy autonomous Moderador de Redes (LAFH/GC-Red, per docs/research-lafh-knowledge-management.md) for a Seed Hypermedia community. Skill already authored under seed-knowledge-manager/.

Stack:

    Local Seed daemon on oc.hyper.media (Go binary seed-daemon, default HTTP API on :55001, gRPC on :55002, P2P on :55000). seed-cli talks to it via -s http://127.0.0.1:55001. Means content is fetched from the network into a local store, then queried locally — no round-trip-per-call to remote hyper.media.

    HKUDS/nanobot as agent runtime (Python pip, JSON config, MCP stdio, optional bwrap sandbox).

    DeepSeek as LLM (OpenAI-compatible).

    Custom stdio MCP wrapper around seed-cli for security envelope, rate limits, audit logging.

    Telegram channel as secondary surface for ops chat with the operator (primary surface: Seed comments).

Headline goal: prove an agent can be governed by Seed documents, not local markdown.

Decisions (locked in)

    Seed daemon: runs locally on oc.hyper.media (Docker image ghcr.io/seed-hypermedia/seed-daemon from backend/cmd/seed-daemon/Dockerfile, ports 55000/1/2).

    Identity: agent has its own Ed25519 key (knowledge-manager, account KM_AID) stored in the same OS keyring the local daemon uses (libsecret on Linux). Owner grants WRITER on --path / of the site.

    Write scope: agent may edit any document under the site. Rules doc still defines deny_write_paths (governance docs themselves, plus optional opt-out areas).

    Telegram: secondary channel, operator-only (channels.telegram.allowFrom = [<OPS_TELEGRAM_ID>]). Used to chat about the agent and the server, not for community member queries.

    All other prior decisions stand: HKUDS/nanobot, DeepSeek, mention-driven via Seed comments AND document mentions, 60s polling, en default locale, governance via Seed docs, bootstrap-on-first-run, full audit trail in km-logs/.

Why local daemon helps

    Activity polling, citation lookups, document fetches all hit 127.0.0.1:55001 → low latency, no rate limit risk, works during hyper.media outages.

    The daemon also pins / replicates the site content locally, giving us a real P2P peer rather than a thin client.

    seed-cli keys live in the same OS keyring the daemon uses (per frontend/apps/cli/docs/KEYS.md), so signing operations don't require key duplication.

    Cost: ~one Docker container, a few hundred MB on disk, plus the daemon's P2P traffic.

Architecture

oc.hyper.media (Ubuntu, ssh ubuntu@) └── /home/km/ # system user `km`, linger enabled ├── seed-daemon/ # docker compose: data + config volumes │ ├── compose.yaml │ └── data/ # persistent state (DB, IPFS blocks, etc.) ├── .nanobot/ │ ├── config.json # providers, agents, tools.mcpServers, channels.telegram │ └── workspace/skill/ # rsynced from repo's seed-knowledge-manager/ ├── km-agent/ │ └── mcp/seed-cli-mcp/ # custom stdio MCP server wrapping seed-cli ├── km-state/ # ephemeral runtime state │ ├── activity-cursor.json │ ├── inbox.jsonl │ ├── processed.jsonl │ ├── rate-counters.json │ └── rules.cache.json └── km-logs/ # full audit log of every agent action ├── runs/2026-05-05T14-02Z__poll-mentions__<ulid>/ │ ├── meta.json # trigger, KM_AID, env hash, start, end, wall_ms │ ├── trace.jsonl # ordered events with timestamps │ ├── llm.jsonl # prompts, completions, reasoning, tokens │ ├── tools.jsonl # MCP tool calls + latencies │ ├── seed-cli.jsonl # argv + stdout + stderr + exit + ms │ ├── stdout.log # raw nanobot stdout │ └── stderr.log # raw nanobot stderr ├── current -> runs/<latest> # symlink to most recent └── index.jsonl # one summary line per run systemd --user units (linger keeps them alive after logout): seed-daemon.service # `docker compose up` for the daemon nanobot-gateway.service # `nanobot gateway` km-bootstrap.service # one-shot, ensures governance docs exist km-poll.timer/.service # `nanobot agent -m "/poll-mentions"` every 60s km-boletin.timer/.service # Mon 09:00 → /run-capability boletin --period last-7d km-health.timer/.service # 1st of month 09:00 → /run-capability network-health km-gap.timer/.service # Wed 10:00 → /run-capability gap-detection External: api.deepseek.com, telegram bot API, the Seed P2P network (via daemon).

Governance via Seed docs (recap)

Same as previous version. Owner-editable Seed documents at fixed paths drive policy:


Rules YAML — now allow_write_paths defaults to [/] (whole site):

--- type: agent-rules schema_version: 1 allow_write_paths: ["/"] deny_write_paths: - /agents/knowledge-manager/charter - /agents/knowledge-manager/rules - /agents/knowledge-manager/runbook - /agents/knowledge-manager/allowlist caps: max_documents_per_run: 1 max_comments_per_run: 5 max_comments_per_day: 30 poll_interval_seconds: 60 mentions: trigger: "@knowledge-manager" invoker_source: "writer-capabilities" moderation: blocked_authors: [] draft_only: false language: en ---

Wrapper enforces: deny_paths > allow_paths > caps. Governance docs are always denied so the agent can't rewrite its own constraints.

Mentions, reactions, audit logging

Same as previous plan version (mention syntax @[Name](hm://aid) in comments and document blocks; replies always via comment, block-anchored where possible; full per-run logs under km-logs/runs/<id>/ with meta, trace, llm (incl. DeepSeek reasoning_content), tools, seed-cli, raw stdout/stderr; secrets redacted; km-log Bash helper for SSH browsing; logrotate 30d / 5GB).

Phased execution

Each phase ships a verifiable artifact. Run them one at a time. After each phase: smoke-test, commit code, then move on.

Phase 0 — Repo scaffolding (local, ~30min)

Outcome: directory seed-knowledge-manager/agent/ with empty placeholders + the operator README skeleton. No deploy yet.

Tasks:

Verify: tree seed-knowledge-manager/agent/ shows the layout; pnpm typecheck still passes (no real code yet).

Phase 1 — Server bootstrap (oc.hyper.media)

Outcome: server has all OS dependencies, the km user, and Docker-based Seed daemon running and synced.

Tasks:

    SSH ubuntu@oc.hyper.media. Install: python3.12 python3.12-venv pipx libsecret-1-0 libsecret-tools dbus-user-session bubblewrap nodejs npm jq curl docker.io docker-compose-plugin logrotate rsync.

    Create user km, loginctl enable-linger km. Add km to docker group.

    As km: mkdir -p ~/seed-daemon/data && cd ~/seed-daemon. Add compose.yaml:

    services: seed-daemon: image: ghcr.io/seed-hypermedia/seed-daemon:latest restart: unless-stopped ports: - "127.0.0.1:55001:55001" # HTTP - "127.0.0.1:55002:55002" # gRPC - "55000:55000/tcp" # P2P - "55000:55000/udp" volumes: - ./data:/data environment: - SEED_DAEMON_FLAGS=--data.dir=/data

    docker compose up -d. Tail logs docker compose logs -f until daemon reports healthy on 127.0.0.1:55001.

    Create user-systemd unit seed-daemon.service that runs docker compose up so it survives reboots.

Verify (must pass before phase 2):

Phase 2 — Agent identity + capability grant

Outcome: agent's Ed25519 key in keyring, owner has granted WRITER on the site, contact published.

Tasks (as km):

    npx -y @seed-hypermedia/cli -s http://127.0.0.1:55001 key generate --name knowledge-manager --show-mnemonic. Capture mnemonic OFFLINE. Capture KM_AID.

    On owner's machine (with owner key in their keyring):

    seed-cli capability create --delegate <KM_AID> --role WRITER --path / --label "knowledge-manager" --key <owner> seed-cli contact create --subject <KM_AID> --name "Knowledge Manager" --key <owner>

    From km: seed-cli account capabilities <SITE_AID> confirms KM_AID is listed as WRITER on /.

Verify:

    From km: create + delete a throwaway document under any path → succeeds.

    Owner sees "Knowledge Manager" appear with avatar in the site UI.

Phase 3 — seed-cli MCP wrapper + tests (local repo)

Outcome: seed-knowledge-manager/agent/mcp/seed-cli-mcp/ is a working Node MCP server with unit tests, runnable on macOS without server access.

Tasks:

    Set up Node package: TS + Vitest + @modelcontextprotocol/sdk. package.json name @km/seed-cli-mcp, bin: ./dist/index.js. Workspace member of pnpm root.

    Implement modules:

      src/governance.ts — fetches the four governance docs via seed_get_document, parses YAML frontmatter, caches 60s, returns Rules.

      src/limits.ts — path allow/deny matcher (globstar), per-run / per-day counter persistence in KM_STATE_DIR/rate-counters.json.

      src/seedcli.ts — typed wrapper: runSeedCli(args), captures argv/exit/stdout/stderr/ms, redacts env values, returns structured result. Force-injects --key knowledge-manager and -s ${SEED_SERVER} for write commands.

      src/audit.ts — current-run dir resolution (created at process start), append-only writers for trace, llm, tools, seed-cli JSONL streams, secret redaction.

      src/mentions.ts — parses Seed activity / citations responses, classifies into mention { kind: comment|doc-block, doc, blockId?, commentId?, author, text }.

      src/state.ts — cursor + inbox + processed-set helpers.

      src/index.ts — registers MCP tools (seed_search, seed_query_space, seed_get_document, seed_list_comments, seed_get_activity, seed_get_citations, seed_list_capabilities, seed_get_governance, seed_create_document, seed_update_document, seed_create_comment, seed_reply_comment, inbox_pop, inbox_mark_done, cursor_get, cursor_set).

    Hardcoded denylist: never accept key *, capability *, account create, document delete <governance-path>.

    Tests (*.test.ts, Vitest): governance YAML parsing, deny-path beats allow-path, rate caps, denylist refusal, draft-only mode forces comment-only, mention parsing for both surfaces, redaction of env values.

    Build: pnpm --filter @km/seed-cli-mcp build produces dist/index.js.

Verify:

    pnpm --filter @km/seed-cli-mcp test green.

    Smoke run locally: MCP_DEBUG=1 node dist/index.js then send tools/list JSON-RPC over stdin → returns the expected toolset.

Phase 4 — nanobot install + governance bootstrap

Outcome: nanobot gateway running on oc.hyper.media; agent has created the four governance docs in the site on first run.

Tasks (as km):

    pipx install nanobot-ai. nanobot --version.

    nanobot onboard (creates ~/.nanobot/{config.json,workspace/}).

    rsync seed-knowledge-manager/~/.nanobot/workspace/skill/ (read-only).

    Deploy ~/.nanobot/secrets.env (mode 600):

    DEEPSEEK_API_KEY=... SEED_SERVER=http://127.0.0.1:55001 SEED_SITE=hm://...

    Write ~/.nanobot/config.json:

    { "providers": { "deepseek": { "apiKey": "${DEEPSEEK_API_KEY}" } }, "agents": { "defaults": { "provider": "deepseek", "model": "deepseek-chat", "systemPrompt": "You are the Knowledge Manager for ${SEED_SITE}. Always call seed_get_governance first; obey it strictly. Methodology: workspace/skill/SKILL.md and templates under workspace/skill/templates/. Default language: en (override only if charter sets language).", "temperature": 0.2, "timezone": "UTC", "idleCompactAfterMinutes": 15 } }, "tools": { "restrictToWorkspace": true, "exec": { "enable": true, "sandbox": "bwrap", "pathAppend": "/usr/bin:/usr/local/bin" }, "web": { "enable": true, "search": { "provider": "duckduckgo", "maxResults": 5 } }, "mcpServers": { "seed": { "command": "node", "args": ["/home/km/km-agent/mcp/seed-cli-mcp/dist/index.js"], "toolTimeout": 60, "env": { "SEED_SERVER": "${SEED_SERVER}", "SEED_SITE": "${SEED_SITE}", "KM_KEY_NAME": "knowledge-manager", "KM_STATE_DIR": "/home/km/km-state", "KM_LOGS_DIR": "/home/km/km-logs" } } } }, "channels": {} }

    Deploy nanobot-gateway.service and km-bootstrap.service (oneshot, runs nanobot agent -m "/bootstrap-governance").

    systemctl --user daemon-reload && systemctl --user enable --now nanobot-gateway.

    systemctl --user start km-bootstrap.service.

Verify:

    The four governance docs exist in the site at /agents/knowledge-manager/{charter,rules,runbook,allowlist}.

    A run dir exists under km-logs/runs/...__bootstrap__<ulid>/ with meta.json, trace.jsonl, seed-cli.jsonl showing the four document create calls.

Phase 5 — Mention polling + reaction

Outcome: writer mentions in comments and documents trigger an agent reply within 2 minutes.

Tasks:

    Deploy km-poll.timer/.service (60s cadence).

    System prompt addendum (committed in repo): the /poll-mentions flow:

      seed_get_governance → rules.

      seed_list_capabilities ${SEED_SITE} → writer set.

      cursor_get → token.

      seed_get_activity --token <cursor> → events. Filter mentions to KM_AID.

      For each mention, if author ∈ writers and not in processed.jsonlinbox_pop queue.

      For each queued mention: classify against capabilities 1–7 in SKILL.md; respond via seed_reply_comment (comment-mention) or seed_create_comment <doc>#<blockId> (doc-mention).

      cursor_set newer.

    Deploy km-log Bash helper to /home/km/.local/bin/km-log.

    Deploy logrotate user config.

Verify:

    From a writer account, comment @[Knowledge Manager](hm://<KM_AID>) what does this community know about X? → reply within 60s.

    From the same account, edit a doc and add inline mention → block-anchored comment within 60s.

    From a non-writer account, mention → ignored, processed.jsonl records reason: not-allowed.

    km-log tail shows full event sequence with timestamps and DeepSeek reasoning_content.

Phase 6 — Scheduled LAFH cadences

Outcome: weekly bulletin, weekly gap report, monthly health report run on schedule.

Tasks:

    Deploy km-boletin.{timer,service} (Mon 09:00 UTC, message /run-capability boletin --period last-7d).

    Deploy km-gap.{timer,service} (Wed 10:00 UTC, message /run-capability gap-detection --period last-7d).

    Deploy km-health.{timer,service} (1st of month 09:00 UTC, message /run-capability network-health --period last-30d).

    Add system prompt support for /run-capability <name> --period <range> (maps capability name → SKILL section).

Verify:

    systemctl --user start km-boletin.service produces a doc at /agents/knowledge-manager/state/boletin/<YYYY-WW>.

    systemctl --user start km-health.service rewrites /agents/knowledge-manager/state/network-health.

    Each run has its own dir under km-logs/runs/.

Phase 7 — Telegram secondary channel

Outcome: operator can chat with the agent over Telegram about agent status, force a poll, query logs, toggle kill-switch.

Tasks:

    Create Telegram bot via @BotFather → token. Get operator's Telegram user ID.

    Add to secrets.env: TELEGRAM_TOKEN=..., OPS_TELEGRAM_ID=<numeric>.

    Edit ~/.nanobot/config.json:

    "channels": { "sendProgress": true, "telegram": { "enabled": true, "token": "${TELEGRAM_TOKEN}", "allowFrom": ["${OPS_TELEGRAM_ID}"] } }

    systemctl --user restart nanobot-gateway.

    Extend the agent's system prompt with operator-only verbs (/status, /poll-now, /show-rules, /last-runs, /draft-only on|off). These never write to Seed; they only read state and emit human-formatted Telegram replies.

    Document in operator README that allowFrom is locked to ops only — community members must use Seed comments, not Telegram.

Verify:

    /start on Telegram returns a welcome.

    Send /status from operator's account → bot responds with daemon health, last run time, comments-today count.

    Send /status from a different Telegram account → silently ignored (allowFrom enforced).

    Send /draft-only on → check next mention reply is a draft comment.

Phase 8 — Audit-log polish + verification suite

Outcome: full smoke test of every flow; logs make sense from SSH.

Tasks:

    Run all 19 verification steps end-to-end (combined from earlier plan plus Telegram).

    Capture screenshots / log excerpts in seed-knowledge-manager/agent/README.md.

Phase 9 — Future / deferred (not in v1)

    Broader "members can invoke" mode (mentions.invoker_source: allowlist-doc).

    Seed-native skill files (currently on disk).

    Heartbeat-style autonomous to-dos in Seed (no checkbox primitive yet).

    Multi-site moderation.

    Web UI for browsing logs.

Files to create / modify (in this repo, across phases)

    seed-knowledge-manager/ — already exists; no changes.

    seed-knowledge-manager/agent/config/config.json — nanobot config template (Phase 4).

    seed-knowledge-manager/agent/seed-daemon/compose.yaml — local daemon compose file (Phase 1).

    seed-knowledge-manager/agent/mcp/seed-cli-mcp/ — Node MCP server + tests (Phase 3).

    seed-knowledge-manager/agent/systemd/{seed-daemon,nanobot-gateway,km-bootstrap,km-poll{.service,.timer},km-boletin{.service,.timer},km-health{.service,.timer},km-gap{.service,.timer}} — all systemd units.

    seed-knowledge-manager/agent/scripts/install.sh — idempotent provisioning script.

    seed-knowledge-manager/agent/scripts/km-log — Bash log helper.

    seed-knowledge-manager/agent/templates/{agent-charter,agent-rules,agent-runbook,agent-allowlist}.md — bootstrap seeds.

    seed-knowledge-manager/agent/logrotate/km-logs.conf — user logrotate (30d / 5GB).

    seed-knowledge-manager/agent/README.md — operator runbook (key gen, capability grant, env vars, deploy, kill-switch, log paths, Telegram setup, daemon volume backup).

    Reuses (no changes):

Verification (full v1 suite)

    1–2. Daemon up locally; seed-cli account list works against http://127.0.0.1:55001.

    3. Agent key generated; capability granted; contact published; throwaway doc round-trip.

    4. MCP wrapper unit tests green; manual tools/list smoke run works.

    5. Bootstrap creates four governance docs; run dir under km-logs/.

    6. Comment-mention from writer → reply ≤60s, block-anchored where applicable.

    7. Document-mention from writer → block-anchored comment reply ≤60s.

    8. Mention from non-writer → ignored, recorded.

    9. draft_only: true → reply is draft comment, no document writes.

    10. deny_write_paths add → write attempt declines with explanatory comment.

    11. Weekly bulletin manual trigger creates state/boletin/<YYYY-W

    12. Health report manual trigger rewrites state/network-health.

    13. Capability revoke → next-tick writes start failing with logged errors.

    14. Wrapper unit tests green in CI.

    15. km-log tail works; meta.json.wall_ms, per-tool latency_ms, DeepSeek reasoning_content all present.

    16. Grep km-logs/ for DEEPSEEK_API_KEY value → zero matches.

    17. logrotate -d dry-run on user config exits clean.

    18. Telegram /status from ops → returns; from non-ops → ignored.

    19. /draft-only on from ops → next mention reply is a draft.

Sources:

Do you like what you are reading? Subscribe to receive updates.

Unsubscribe anytime