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 binaryseed-daemon, default HTTP API on:55001, gRPC on:55002, P2P on:55000).seed-clitalks to it via-shttp://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 remotehyper.media.HKUDS/nanobot as agent runtime (Python pip, JSON config, MCP stdio, optional
bwrapsandbox).DeepSeek as LLM (OpenAI-compatible).
Custom stdio MCP wrapper around
seed-clifor 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 imageghcr.io/seed-hypermedia/seed-daemonfrombackend/cmd/seed-daemon/Dockerfile, ports 55000/1/2).Identity: agent has its own Ed25519 key (
knowledge-manager, accountKM_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-clikeys live in the same OS keyring the daemon uses (perfrontend/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:
Create
seed-knowledge-manager/agent/{config,mcp/seed-cli-mcp,scripts,systemd,templates,logrotate}with stub files.Stub
seed-knowledge-manager/agent/README.mdwith the operator runbook outline.Stub
templates/agent-charter.md,agent-rules.md,agent-runbook.md,agent-allowlist.md(empty frontmatter + placeholder bodies).
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 curldocker.iodocker-compose-plugin logrotate rsync.Create user
km,loginctl enable-linger km. Addkmtodockergroup.As
km:mkdir -p ~/seed-daemon/data && cd ~/seed-daemon. Addcompose.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=/datadocker compose up -d. Tail logsdocker compose logs -funtil daemon reports healthy on127.0.0.1:55001.Create user-systemd unit
seed-daemon.servicethat runsdocker compose upso it survives reboots.
Verify (must pass before phase 2):
curl -shttp://127.0.0.1:55001/healthz(or/status) returns 200.npx -y @seed-hypermedia/cli -shttp://127.0.0.1:55001account listworks.Daemon survives
reboot.
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 -shttp://127.0.0.1:55001key generate --name knowledge-manager --show-mnemonic. Capture mnemonic OFFLINE. CaptureKM_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.jsonname@km/seed-cli-mcp,bin: ./dist/index.js. Workspace member of pnpm root.Implement modules:
src/governance.ts— fetches the four governance docs viaseed_get_document, parses YAML frontmatter, caches 60s, returnsRules.src/limits.ts— path allow/deny matcher (globstar), per-run / per-day counter persistence inKM_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-managerand-s ${SEED_SERVER}for write commands.src/audit.ts— current-run dir resolution (created at process start), append-only writers fortrace,llm,tools,seed-cliJSONL streams, secret redaction.src/mentions.ts— parses Seed activity / citations responses, classifies intomention { 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 buildproducesdist/index.js.
Verify:
pnpm --filter @km/seed-cli-mcp testgreen.Smoke run locally:
MCP_DEBUG=1 node dist/index.jsthen sendtools/listJSON-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.serviceandkm-bootstrap.service(oneshot, runsnanobot 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>/withmeta.json,trace.jsonl,seed-cli.jsonlshowing the fourdocument createcalls.
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-mentionsflow:seed_get_governance→ rules.seed_list_capabilities ${SEED_SITE}→ writer set.cursor_get→ token.seed_get_activity --token <cursor>→ events. Filter mentions toKM_AID.For each mention, if author ∈ writers and not in
processed.jsonl→inbox_popqueue.For each queued mention: classify against capabilities 1–7 in
SKILL.md; respond viaseed_reply_comment(comment-mention) orseed_create_comment <doc>#<blockId>(doc-mention).cursor_setnewer.
Deploy
km-logBash 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.jsonlrecordsreason: not-allowed.km-log tailshows full event sequence with timestamps and DeepSeekreasoning_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.serviceproduces a doc at/agents/knowledge-manager/state/boletin/<YYYY-WW>.systemctl --user start km-health.servicerewrites/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
allowFromis locked to ops only — community members must use Seed comments, not Telegram.
Verify:
/starton Telegram returns a welcome.Send
/statusfrom operator's account → bot responds with daemon health, last run time, comments-today count.Send
/statusfrom a different Telegram account → silently ignored (allowFromenforced).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):
backend/cmd/seed-daemon/Dockerfileand the published image — local daemon.frontend/apps/cli/docs/CLI-REFERENCE.md,KEYS.md,README.md— seed-cli surface, mention syntax, key storage.seed-knowledge-manager/SKILL.md,templates/,references/— methodology.docs/research-lafh-knowledge-management.md— theory.
Verification (full v1 suite)
1–2. Daemon up locally;
seed-cli account listworks againsthttp://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/listsmoke 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_pathsadd → write attempt declines with explanatory comment.11. Weekly bulletin manual trigger creates
state/boletin/<YYYY-W12. 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 tailworks;meta.json.wall_ms, per-toollatency_ms, DeepSeekreasoning_contentall present.16. Grep
km-logs/forDEEPSEEK_API_KEYvalue → zero matches.17.
logrotate -ddry-run on user config exits clean.18. Telegram
/statusfrom ops → returns; from non-ops → ignored.19.
/draft-only onfrom ops → next mention reply is a draft.
Sources:
backend/cmd/seed-daemon/Dockerfilebackend/config/config.go(default ports 55000/1/2)frontend/apps/cli/docs/CLI-REFERENCE.mdfrontend/apps/cli/docs/KEYS.mdfrontend/apps/cli/README.md(mention syntax + block-level comments)seed-knowledge-manager/SKILL.md
Do you like what you are reading?. Subscribe to receive updates.
Unsubscribe anytime