eleven / ocho Public

Clone
git clone https://amadan.net/eleven/ocho

Plain git — no account needed to clone.

Download

Download this file

1// The `lchat agents` subcommand family (docs/superpowers/specs/
2// 2026-08-05-eleven-claude-agents-design.md):
3//
4// - `lchat agents run` IS the workstation bridge (internal/agents) — run on
5// the machine whose Claude Code sessions a group should share. A pure
6// outbound client in the bot-sidecar mould: it dials the instance, holds
7// its member key and the machine's authority HERE, and opens no ports.
8//
9// Unlike bot/hooks there is no add-agents control verb: the bridge runs on a
10// developer workstation, not the router box, so an operator stands it up by
11// hand — mint an agent invite, write the config, run the command.
12package main
13
14import (
15 "context"
16 "flag"
17 "fmt"
18 "log"
19 "os"
20 "strings"
21
22 "lchat/internal/agents"
23 "lchat/internal/bot"
24)
25
26func runAgentsCmd(args []string) {
27 if len(args) < 1 {
28 fmt.Fprintln(os.Stderr, `usage: lchat agents <command>
29
30commands:
31 run run the workstation bridge: front this machine's Claude Code sessions
32 into the group threads the config grants (config: agents.json)`)
33 os.Exit(2)
34 }
35 switch args[0] {
36 case "run":
37 runAgentsRun(args[1:])
38 default:
39 die("agents: unknown command %q", args[0])
40 }
41}
42
43func runAgentsRun(args []string) {
44 fs := flag.NewFlagSet("agents run", flag.ExitOnError)
45 base := fs.String("base", envOr("LCHAT_BASE", ""), "instance URL (env: LCHAT_BASE)")
46 session := fs.String("session", envOr("LCHAT_SESSION", "agents-session.json"), "member session file (env: LCHAT_SESSION)")
47 config := fs.String("config", envOr("LCHAT_AGENTS_CONFIG", "agents.json"), "bridge config: which groups get which roots (env: LCHAT_AGENTS_CONFIG)")
48 _ = fs.Parse(reorderFlagsFirst(fs, args))
49
50 if *base == "" {
51 die("agents run: set -base (or LCHAT_BASE) to your instance URL")
52 }
53 // The config is the blast radius — fail-closed before touching the network.
54 cfg, err := agents.LoadConfig(*config)
55 if err != nil {
56 die("agents run: %v", err)
57 }
58 // Self-provision on first boot from a one-time agent invite, exactly like
59 // the bot sidecar (#806). Env-only — a flag would leak it into the process
60 // table.
61 sess, err := bot.EnsureSession(strings.TrimRight(*base, "/"), *session, os.Getenv("LCHAT_INVITE"), "Claude", log.Printf)
62 if err != nil {
63 die("agents run: %v", err)
64 }
65 if sess == nil {
66 die("agents run: no session at %s and no LCHAT_INVITE — mint an agent invite (admin → helpers) first", *session)
67 }
68
69 b := agents.New(strings.TrimRight(*base, "/"), sess, cfg, log.Printf)
70 log.Printf("agents run: bridging %d group(s) on %s", len(cfg.Groups), *base)
71 if err := b.Run(context.Background()); err != nil {
72 die("agents run: %v", err)
73 }
74}
75