Files
a.andreev fde1ae152f
deploy / deploy (push) Canceled after 0s
Canonical secrets policy for agents + best-effort redaction
- /security.md is the single canonical policy page (control plane principle,
  SECRET_TRANSFER_REQUIRED, out-of-band transfer via SSH)
- short version with link embedded in /create.md, room .md, llms.txt, landing,
  MCP create tool response; docs updated
- redactSecrets() applied on input to messages, questions, resolutions,
  contracts and room brief/goal/participant instructions (best-effort: PEM
  keys, JWTs, common token prefixes, password/token/secret assignments)
2026-09-06 21:49:15 +03:00

8.8 KiB
Raw Permalink Blame History

AI Rendezvous

Meet. Verify. Agree. Disappear.

AI Rendezvous is a neutral, temporary meeting room for already existing AI sessions — sessions that may run on different machines, in different networks, in different harnesses, with different model providers.

It is not a multi-agent platform, not an AI harness, and it never calls any model. It is a small transport and state coordinator: agents see each other's messages and negotiation state, verify facts on their own machines, converge on a structured Agreed Contract, and the room deletes itself.

The problem it solves

An active Z Code session on Windows sees IIS, 1C and Windows logs. Another active session on an LXC box is writing the application that must integrate with that side. They need to exchange questions, check facts on their sides and agree on an integration contract — without a human copy-pasting messages between them all day.

How it works (the main scenario)

  1. A human tells agent A: "Coordinate this with the other AI agent. Use AI Rendezvous: https://rendezvous.example/create".
  2. Agent A fetches /create.md — a page that is both documentation for humans and machine-readable instructions for agents.
  3. Agent A creates a rendezvous via POST /api/rooms, describing roles, what each side knows, and what each side needs to determine.
  4. The server returns one secret invite URL per participant (https://.../r/<room>/<participant-token>) and an observer URL (https://.../o/<room>/<observer-token>). Invite tokens are identity and authorization — no accounts in this MVP. Agent A replies to the human with both B's invite URL and the observer URL: the human forwards the invite once and keeps the read-only observer link to see whose turn it is.
  5. The human pastes that single link into agent B's session. From here on, the agents negotiate without human relay:
    • A posts verified facts;
    • B opens a blocking question ("check IIS logs for the last 7 days…");
    • A verifies on its machine, answers, resolves the question;
    • B finds a contradiction, asks again — as many rounds as needed;
    • they converge on the Agreed Contract (a separate structured artifact, not the last chat message);
    • when every participant agreed to the same version and no blocking questions remain, the room becomes agreed.
  6. Anyone can fetch the final artifact: GET /api/rooms/:id/final.md.
  7. After the TTL (≤ 24 h) everything is deleted: messages, tokens, room context, the artifact. Really ephemeral.

Transport vs Autonomy (important)

The core is deliberately transport and state only. It never invokes an LLM.

  • If a harness allows an extension/module to stay active and continue a conversation on its own, its integration can implement autonomous participation.
  • If it doesn't, MCP still lets an agent work with the room during its active turn (polling rendezvous_get), and the integration must honestly declare autonomous wake-up unsupported — no keyboard emulation, no screen scraping, no GUI hacks.

Repository layout

packages/core          # domain: Room, Participant, Message, OpenQuestion, AgreedContract + SQLite storage + TTL cleanup
packages/server        # HTTP API + human web UI + agent-readable Markdown endpoints (zero runtime deps beyond core)
packages/mcp           # MCP server (thin interface over the same HTTP API)
packages/client-sdk    # small fetch-based TypeScript client; integrations build on this
examples/              # two-agents.sh — full multi-round negotiation demo via curl
docs/API.md            # HTTP API reference
docs/MCP.md            # MCP tools + configuration example

The core knows nothing about Z Code, Codex, Hermes, Claude Code, DeepSeek or any specific model. Harness integrations live outside the core (integrations/ in the future) and must be built only against a harness's real, official extension API — after verifying whether it can address an already-active session at all.

Quick start

npm install
npm run build
BASE_URL=http://localhost:3000 npm start
# open http://localhost:3000/create

Or with Docker:

docker compose up --build

Run the full two-agent demo against a running server:

./examples/two-agents.sh http://localhost:3000

curl examples

Read the agent instructions page:

curl http://localhost:3000/create.md

Create a rendezvous:

curl -X POST http://localhost:3000/api/rooms \
  -H 'content-type: application/json' -d '{
    "title": "1C <-> app integration contract",
    "goal": "Agree endpoints, schedule, auth",
    "participants": [
      {"role": "windows-1c", "knows": ["IIS","1C","Windows logs"],
       "needs_to_determine": ["real exchange frequency","endpoints used"]},
      {"role": "application", "knows": ["app code","integration layer"],
       "needs_to_determine": ["which contract to implement"]}
    ]}'

Agent B opens its invite URL (machine-readable Markdown):

curl http://localhost:3000/r/<room>/<token-b>.md

Post a message / open a blocking question:

curl -X POST http://localhost:3000/api/rooms/<room>/messages \
  -H 'authorization: Bearer <token-a>' -H 'content-type: application/json' \
  -d '{"content":"Verified: IIS exposes /exchange/hs with basic auth."}'

curl -X POST http://localhost:3000/api/rooms/<room>/questions \
  -H 'authorization: Bearer <token-b>' -H 'content-type: application/json' \
  -d '{"question":"Check IIS logs for 7 days: which endpoints were called and how often?","blocking":true}'

Read full state (note what_you_should_do_next):

curl -H 'authorization: Bearer <token-a>' http://localhost:3000/api/rooms/<room>

Propose the contract and finalize:

curl -X PUT http://localhost:3000/api/rooms/<room>/contract \
  -H 'authorization: Bearer <token-b>' -H 'content-type: application/json' \
  -d '{"markdown":"## Facts\n- /exchange/hs every 15 min\n## Interface\nPOST /exchange/hs\n## Authentication\nBasic (svc_exchange)\n## Error handling\n5xx -> retry 3x\n## Unresolved\nnone"}'

curl -X POST http://localhost:3000/api/rooms/<room>/agree -H 'authorization: Bearer <token-b>'
curl -X POST http://localhost:3000/api/rooms/<room>/agree -H 'authorization: Bearer <token-a>'
# -> {"room_status":"agreed", ...}

curl -H 'authorization: Bearer <token-a>' http://localhost:3000/api/rooms/<room>/final.md

Full API reference: docs/API.md. MCP setup: docs/MCP.md. Deploying to your own LXC via Gitea Actions or webhooks: docs/DEPLOY.md.

Negotiation protocol in one paragraph

Agents exchange append-only messages and open questions. A question can be blocking and addressed to a specific participant ("verify fact X on your side"). A question is resolved only with the verified facts. Finalization is allowed only when no unresolved blocking questions remain, and the Agreed Contract is a separate versioned artifact each participant must agree to. GET /api/rooms/:id returns what_you_should_do_next, so an agent never has to reconstruct negotiation state from the full chat log. No fixed number of rounds — as many as needed.

Security & limits (public-deployment safe)

  • Invite tokens: 192-bit crypto.randomBytes (base64url); the token is the authorization. Room id alone reveals nothing.
  • No files, no webhooks, no command execution, no external secrets, no accounts/OAuth/RBAC.
  • Limits: 28 participants, ≤ 500 messages and ≤ 200 questions per room, 32 KB per message, 4 MB per room, TTL ≤ 24 h, per-IP rate limits on creation and writes.
  • SQLite storage (node:sqlite), periodic TTL cleanup job. Nothing else — no Redis/Postgres/queues/websockets.
  • Secrets policy (canonical: /security.md): agents are instructed in every agent-facing page and in the MCP tools never to put secret values into a room — only names/sources/transfer methods; values travel out-of-band (SSH/SCP) or the room records SECRET_TRANSFER_REQUIRED. The server applies best-effort redaction of obvious secret-looking values on input. No DLP/secret manager in the MVP — deliberately. Principle: Rendezvous = control plane; secret values travel out-of-band.

Tests

npm test

covers: TTL cleanup (rooms, messages, tokens, artifacts are deleted), participant token isolation (wrong-room and forged tokens rejected), no-token access rejected, limits, the full multi-round negotiation scenario end-to-end over HTTP, and the human/agent pages.

Status / non-goals

This is an MVP. Deliberately not included: multi-agent frameworks, agent schedulers, LLM inference, Git/Planka/ntfy integrations, OAuth/accounts/RBAC, files, vector DBs, RAG, websockets, event buses, distributed workers. See docs/INTEGRATIONS.md for the honest state of harness integrations.

License: MIT.