● Zion Boggan
repos/Darwin/deck/darwin-emit
zionboggan.com ↗
103 lines · text
History for this file →
1
#!/usr/bin/env python3
2
"""
3
darwin-emit  - POST a contract-§1 event to the Darwin Deck event bus.
4
 
5
The forward hook for true `agents-of-agents` nesting: any process (a spawner,
6
a scheduler, a remote agent, a shell hook) can self-report into the live tree.
7
A spawner emits a `child_spawned` carrying its own --parent-id so the child
8
nests under it to any depth.
9
 
10
Deck endpoint (default): http://REDACTED-IP:9893/event
11
Contract: /shared/projects/darwin/deck/CONTRACTS.md §1
12
 
13
USAGE
14
  darwin-emit --agent-id ID [options]
15
  darwin-emit -a ID -t child_spawned -p PARENT_ID -l "Build gateway" -m glm --host ct247
16
 
17
OPTIONS  (env var fallback in parens; CLI wins)
18
  -a, --agent-id   ID    stable id for this agent run        (DARWIN_AGENT_ID)   [required]
19
  -p, --parent-id  ID    spawner id -> builds the tree edge  (DARWIN_PARENT_ID)
20
  -t, --type       T     spawned|tool_call|child_spawned|returned|error|token_tick
21
                                                             (DARWIN_TYPE, default: spawned)
22
  -l, --label      S     human label                         (DARWIN_LABEL)
23
  -m, --model      S     sonnet|opus|glm-5.2|codex|gpt-5.5|… (DARWIN_MODEL, default: sonnet)
24
  -s, --status     S     running|done|error|paused           (DARWIN_STATUS, default: running)
25
      --host       S     ct215|ct241|ct247|…                 (DARWIN_HOST, default: ct215)
26
      --tokens     N     cumulative token count               (DARWIN_TOKENS, default: 0)
27
      --tool       S     tool name (for tool_call)            (DARWIN_TOOL)
28
      --session    S     session id                           (DARWIN_SESSION)
29
      --deck-url   URL   override Deck base url                (DARWIN_DECK_URL)
30
  -q, --quiet            no stdout on success
31
 
32
EXAMPLES
33
  # a spawner registers a freshly-spawned child under itself
34
  darwin-emit -a child_abc -p $MY_AGENT_ID -t child_spawned -l "scan repo" -m glm --host ct247
35
 
36
  # heartbeat / token tick
37
  darwin-emit -a child_abc -t token_tick --tokens 53542
38
 
39
  # mark done
40
  darwin-emit -a child_abc -t returned -s done
41
 
42
EXIT  0 ok · 2 bad args · 3 POST failed
43
"""
44
import argparse
45
import json
46
import os
47
import sys
48
import urllib.request
49
from datetime import datetime, timezone
50
 
51
 
52
def main() -> int:
53
    p = argparse.ArgumentParser(add_help=True, description="Emit a Darwin Deck event.")
54
    p.add_argument("-a", "--agent-id", default=os.environ.get("DARWIN_AGENT_ID"))
55
    p.add_argument("-p", "--parent-id", default=os.environ.get("DARWIN_PARENT_ID"))
56
    p.add_argument("-t", "--type", default=os.environ.get("DARWIN_TYPE", "spawned"))
57
    p.add_argument("-l", "--label", default=os.environ.get("DARWIN_LABEL", ""))
58
    p.add_argument("-m", "--model", default=os.environ.get("DARWIN_MODEL", "sonnet"))
59
    p.add_argument("-s", "--status", default=os.environ.get("DARWIN_STATUS", "running"))
60
    p.add_argument("--host", default=os.environ.get("DARWIN_HOST", "ct215"))
61
    p.add_argument("--tokens", type=int, default=int(os.environ.get("DARWIN_TOKENS", "0")))
62
    p.add_argument("--tool", default=os.environ.get("DARWIN_TOOL"))
63
    p.add_argument("--session", default=os.environ.get("DARWIN_SESSION", ""))
64
    p.add_argument("--deck-url", default=os.environ.get("DARWIN_DECK_URL", "http://REDACTED-IP:9893"))
65
    p.add_argument("-q", "--quiet", action="store_true")
66
    args = p.parse_args()
67
 
68
    if not args.agent_id:
69
        sys.stderr.write("darwin-emit: --agent-id (or DARWIN_AGENT_ID) is required\n")
70
        return 2
71
 
72
    event = {
73
        "ts": datetime.now(timezone.utc).isoformat(),
74
        "agent_id": args.agent_id,
75
        "parent_id": args.parent_id,
76
        "type": args.type,
77
        "label": args.label,
78
        "model": args.model,
79
        "status": args.status,
80
        "tokens": args.tokens,
81
        "host": args.host,
82
        "session": args.session,
83
    }
84
    if args.tool:
85
        event["tool"] = args.tool
86
 
87
    url = args.deck_url.rstrip("/") + "/event"
88
    data = json.dumps(event).encode()
89
    req = urllib.request.Request(url, data=data, headers={"Content-Type": "application/json"}, method="POST")
90
    try:
91
        with urllib.request.urlopen(req, timeout=5) as resp:
92
            body = resp.read().decode()
93
    except Exception as e:  # noqa: BLE001 - deck down must never break a spawner
94
        sys.stderr.write(f"darwin-emit: POST failed: {e}\n")
95
        return 3
96
 
97
    if not args.quiet:
98
        print(body)
99
    return 0
100
 
101
 
102
if __name__ == "__main__":
103
    sys.exit(main())