ScuttleBot

feat: Makefile, release workflow, and CLI improvements Makefile: - add 'all' target building every binary to bin/ - add fmt, vet, install targets - use $@ in bin/* rules Release workflow: - fix Go version: go-version-file: go.mod - add claude-relay, codex-relay, gemini-relay to release artifacts scuttlectl CLI: - add 'backend list', 'backend get', 'backend delete' subcommands - add 'operator' to agent register type options - remove misleading 'logs tail (coming soon)' stub - add ListLLMBackends to apiclient

lmata 2026-04-01 19:10 trunk
Commit 73ef90f3712fce73de4bb65097730222bdaae4c3cd5df4ddddb982001035bf88
--- .github/workflows/release.yml
+++ .github/workflows/release.yml
@@ -26,23 +26,26 @@
2626
steps:
2727
- uses: actions/checkout@v4
2828
2929
- uses: actions/setup-go@v5
3030
with:
31
- go-version: "1.22"
31
+ go-version-file: go.mod
3232
cache: true
3333
3434
- name: Build binaries
3535
env:
3636
GOOS: ${{ matrix.goos }}
3737
GOARCH: ${{ matrix.goarch }}
3838
run: |
3939
SUFFIX="${{ matrix.goos }}-${{ matrix.goarch }}"
40
- go build -ldflags="-X main.version=${{ github.ref_name }}" \
41
- -o "dist/scuttlebot-${SUFFIX}" ./cmd/scuttlebot
42
- go build -ldflags="-X main.version=${{ github.ref_name }}" \
43
- -o "dist/scuttlectl-${SUFFIX}" ./cmd/scuttlectl
40
+ LDFLAGS="-X main.version=${{ github.ref_name }}"
41
+ mkdir -p dist
42
+ go build -ldflags="${LDFLAGS}" -o "dist/scuttlebot-${SUFFIX}" ./cmd/scuttlebot
43
+ go build -ldflags="${LDFLAGS}" -o "dist/scuttlectl-${SUFFIX}" ./cmd/scuttlectl
44
+ go build -ldflags="${LDFLAGS}" -o "dist/claude-relay-${SUFFIX}" ./cmd/claude-relay
45
+ go build -ldflags="${LDFLAGS}" -o "dist/codex-relay-${SUFFIX}" ./cmd/codex-relay
46
+ go build -ldflags="${LDFLAGS}" -o "dist/gemini-relay-${SUFFIX}" ./cmd/gemini-relay
4447
4548
- name: Upload to release
4649
uses: softprops/action-gh-release@v2
4750
with:
4851
files: dist/*
4952
--- .github/workflows/release.yml
+++ .github/workflows/release.yml
@@ -26,23 +26,26 @@
26 steps:
27 - uses: actions/checkout@v4
28
29 - uses: actions/setup-go@v5
30 with:
31 go-version: "1.22"
32 cache: true
33
34 - name: Build binaries
35 env:
36 GOOS: ${{ matrix.goos }}
37 GOARCH: ${{ matrix.goarch }}
38 run: |
39 SUFFIX="${{ matrix.goos }}-${{ matrix.goarch }}"
40 go build -ldflags="-X main.version=${{ github.ref_name }}" \
41 -o "dist/scuttlebot-${SUFFIX}" ./cmd/scuttlebot
42 go build -ldflags="-X main.version=${{ github.ref_name }}" \
43 -o "dist/scuttlectl-${SUFFIX}" ./cmd/scuttlectl
 
 
 
44
45 - name: Upload to release
46 uses: softprops/action-gh-release@v2
47 with:
48 files: dist/*
49
--- .github/workflows/release.yml
+++ .github/workflows/release.yml
@@ -26,23 +26,26 @@
26 steps:
27 - uses: actions/checkout@v4
28
29 - uses: actions/setup-go@v5
30 with:
31 go-version-file: go.mod
32 cache: true
33
34 - name: Build binaries
35 env:
36 GOOS: ${{ matrix.goos }}
37 GOARCH: ${{ matrix.goarch }}
38 run: |
39 SUFFIX="${{ matrix.goos }}-${{ matrix.goarch }}"
40 LDFLAGS="-X main.version=${{ github.ref_name }}"
41 mkdir -p dist
42 go build -ldflags="${LDFLAGS}" -o "dist/scuttlebot-${SUFFIX}" ./cmd/scuttlebot
43 go build -ldflags="${LDFLAGS}" -o "dist/scuttlectl-${SUFFIX}" ./cmd/scuttlectl
44 go build -ldflags="${LDFLAGS}" -o "dist/claude-relay-${SUFFIX}" ./cmd/claude-relay
45 go build -ldflags="${LDFLAGS}" -o "dist/codex-relay-${SUFFIX}" ./cmd/codex-relay
46 go build -ldflags="${LDFLAGS}" -o "dist/gemini-relay-${SUFFIX}" ./cmd/gemini-relay
47
48 - name: Upload to release
49 uses: softprops/action-gh-release@v2
50 with:
51 files: dist/*
52
+43 -22
--- Makefile
+++ Makefile
@@ -1,52 +1,73 @@
1
-.PHONY: build test lint clean install-codex-relay install-gemini-relay install-claude-relay test-smoke
1
+.PHONY: all build fmt vet lint test test-smoke clean install \
2
+ install-claude-relay install-codex-relay install-gemini-relay
3
+
4
+BINS := bin/scuttlebot bin/scuttlectl bin/claude-relay bin/codex-relay \
5
+ bin/gemini-relay bin/claude-agent bin/codex-agent bin/gemini-agent \
6
+ bin/fleet-cmd
7
+
8
+all: $(BINS)
29
310
build:
411
go build ./...
512
13
+fmt:
14
+ gofmt -w ./
15
+
16
+vet:
17
+ go vet ./...
18
+
19
+lint:
20
+ golangci-lint run
21
+
622
test:
723
go test ./...
824
925
test-smoke:
1026
bash tests/smoke/test-installers.sh
1127
12
-lint:
13
- golangci-lint run
28
+# Install daemon + CLI to $(GOPATH)/bin (or ~/go/bin).
29
+install:
30
+ go install ./cmd/scuttlebot ./cmd/scuttlectl
1431
1532
clean:
16
- rm -f bin/scuttlebot bin/scuttlectl bin/claude-agent bin/codex-agent bin/gemini-agent bin/codex-relay bin/gemini-relay bin/claude-relay bin/fleet-cmd
33
+ rm -f $(BINS)
34
+
35
+# --- relay install helpers ---
36
+
37
+install-claude-relay:
38
+ bash skills/scuttlebot-relay/scripts/install-claude-relay.sh
1739
1840
install-codex-relay:
1941
bash skills/openai-relay/scripts/install-codex-relay.sh
2042
2143
install-gemini-relay:
2244
bash skills/gemini-relay/scripts/install-gemini-relay.sh
2345
24
-install-claude-relay:
25
- bash skills/scuttlebot-relay/scripts/install-claude-relay.sh
46
+# --- individual bin targets ---
2647
2748
bin/scuttlebot:
28
- go build -o bin/scuttlebot ./cmd/scuttlebot
49
+ go build -o $@ ./cmd/scuttlebot
2950
3051
bin/scuttlectl:
31
- go build -o bin/scuttlectl ./cmd/scuttlectl
32
-
33
-bin/claude-agent:
34
- go build -o bin/claude-agent ./cmd/claude-agent
35
-
36
-bin/codex-agent:
37
- go build -o bin/codex-agent ./cmd/codex-agent
38
-
39
-bin/gemini-agent:
40
- go build -o bin/gemini-agent ./cmd/gemini-agent
52
+ go build -o $@ ./cmd/scuttlectl
53
+
54
+bin/claude-relay:
55
+ go build -o $@ ./cmd/claude-relay
4156
4257
bin/codex-relay:
43
- go build -o bin/codex-relay ./cmd/codex-relay
58
+ go build -o $@ ./cmd/codex-relay
4459
4560
bin/gemini-relay:
46
- go build -o bin/gemini-relay ./cmd/gemini-relay
61
+ go build -o $@ ./cmd/gemini-relay
62
+
63
+bin/claude-agent:
64
+ go build -o $@ ./cmd/claude-agent
65
+
66
+bin/codex-agent:
67
+ go build -o $@ ./cmd/codex-agent
4768
48
-bin/claude-relay:
49
- go build -o bin/claude-relay ./cmd/claude-relay
69
+bin/gemini-agent:
70
+ go build -o $@ ./cmd/gemini-agent
5071
5172
bin/fleet-cmd:
52
- go build -o bin/fleet-cmd ./cmd/fleet-cmd
73
+ go build -o $@ ./cmd/fleet-cmd
5374
--- Makefile
+++ Makefile
@@ -1,52 +1,73 @@
1 .PHONY: build test lint clean install-codex-relay install-gemini-relay install-claude-relay test-smoke
 
 
 
 
 
 
 
2
3 build:
4 go build ./...
5
 
 
 
 
 
 
 
 
 
6 test:
7 go test ./...
8
9 test-smoke:
10 bash tests/smoke/test-installers.sh
11
12 lint:
13 golangci-lint run
 
14
15 clean:
16 rm -f bin/scuttlebot bin/scuttlectl bin/claude-agent bin/codex-agent bin/gemini-agent bin/codex-relay bin/gemini-relay bin/claude-relay bin/fleet-cmd
 
 
 
 
 
17
18 install-codex-relay:
19 bash skills/openai-relay/scripts/install-codex-relay.sh
20
21 install-gemini-relay:
22 bash skills/gemini-relay/scripts/install-gemini-relay.sh
23
24 install-claude-relay:
25 bash skills/scuttlebot-relay/scripts/install-claude-relay.sh
26
27 bin/scuttlebot:
28 go build -o bin/scuttlebot ./cmd/scuttlebot
29
30 bin/scuttlectl:
31 go build -o bin/scuttlectl ./cmd/scuttlectl
32
33 bin/claude-agent:
34 go build -o bin/claude-agent ./cmd/claude-agent
35
36 bin/codex-agent:
37 go build -o bin/codex-agent ./cmd/codex-agent
38
39 bin/gemini-agent:
40 go build -o bin/gemini-agent ./cmd/gemini-agent
41
42 bin/codex-relay:
43 go build -o bin/codex-relay ./cmd/codex-relay
44
45 bin/gemini-relay:
46 go build -o bin/gemini-relay ./cmd/gemini-relay
 
 
 
 
 
 
47
48 bin/claude-relay:
49 go build -o bin/claude-relay ./cmd/claude-relay
50
51 bin/fleet-cmd:
52 go build -o bin/fleet-cmd ./cmd/fleet-cmd
53
--- Makefile
+++ Makefile
@@ -1,52 +1,73 @@
1 .PHONY: all build fmt vet lint test test-smoke clean install \
2 install-claude-relay install-codex-relay install-gemini-relay
3
4 BINS := bin/scuttlebot bin/scuttlectl bin/claude-relay bin/codex-relay \
5 bin/gemini-relay bin/claude-agent bin/codex-agent bin/gemini-agent \
6 bin/fleet-cmd
7
8 all: $(BINS)
9
10 build:
11 go build ./...
12
13 fmt:
14 gofmt -w ./
15
16 vet:
17 go vet ./...
18
19 lint:
20 golangci-lint run
21
22 test:
23 go test ./...
24
25 test-smoke:
26 bash tests/smoke/test-installers.sh
27
28 # Install daemon + CLI to $(GOPATH)/bin (or ~/go/bin).
29 install:
30 go install ./cmd/scuttlebot ./cmd/scuttlectl
31
32 clean:
33 rm -f $(BINS)
34
35 # --- relay install helpers ---
36
37 install-claude-relay:
38 bash skills/scuttlebot-relay/scripts/install-claude-relay.sh
39
40 install-codex-relay:
41 bash skills/openai-relay/scripts/install-codex-relay.sh
42
43 install-gemini-relay:
44 bash skills/gemini-relay/scripts/install-gemini-relay.sh
45
46 # --- individual bin targets ---
 
47
48 bin/scuttlebot:
49 go build -o $@ ./cmd/scuttlebot
50
51 bin/scuttlectl:
52 go build -o $@ ./cmd/scuttlectl
53
54 bin/claude-relay:
55 go build -o $@ ./cmd/claude-relay
 
 
 
 
 
 
56
57 bin/codex-relay:
58 go build -o $@ ./cmd/codex-relay
59
60 bin/gemini-relay:
61 go build -o $@ ./cmd/gemini-relay
62
63 bin/claude-agent:
64 go build -o $@ ./cmd/claude-agent
65
66 bin/codex-agent:
67 go build -o $@ ./cmd/codex-agent
68
69 bin/gemini-agent:
70 go build -o $@ ./cmd/gemini-agent
71
72 bin/fleet-cmd:
73 go build -o $@ ./cmd/fleet-cmd
74
--- cmd/scuttlectl/internal/apiclient/apiclient.go
+++ cmd/scuttlectl/internal/apiclient/apiclient.go
@@ -81,10 +81,15 @@
8181
8282
// ListChannels sends GET /v1/channels and returns raw JSON.
8383
func (c *Client) ListChannels() (json.RawMessage, error) {
8484
return c.get("/v1/channels")
8585
}
86
+
87
+// ListLLMBackends sends GET /v1/llm/backends and returns raw JSON.
88
+func (c *Client) ListLLMBackends() (json.RawMessage, error) {
89
+ return c.get("/v1/llm/backends")
90
+}
8691
8792
// GetLLMBackend sends GET /v1/llm/backends and finds the named backend, returning raw JSON.
8893
func (c *Client) GetLLMBackend(name string) (json.RawMessage, error) {
8994
raw, err := c.get("/v1/llm/backends")
9095
if err != nil {
9196
--- cmd/scuttlectl/internal/apiclient/apiclient.go
+++ cmd/scuttlectl/internal/apiclient/apiclient.go
@@ -81,10 +81,15 @@
81
82 // ListChannels sends GET /v1/channels and returns raw JSON.
83 func (c *Client) ListChannels() (json.RawMessage, error) {
84 return c.get("/v1/channels")
85 }
 
 
 
 
 
86
87 // GetLLMBackend sends GET /v1/llm/backends and finds the named backend, returning raw JSON.
88 func (c *Client) GetLLMBackend(name string) (json.RawMessage, error) {
89 raw, err := c.get("/v1/llm/backends")
90 if err != nil {
91
--- cmd/scuttlectl/internal/apiclient/apiclient.go
+++ cmd/scuttlectl/internal/apiclient/apiclient.go
@@ -81,10 +81,15 @@
81
82 // ListChannels sends GET /v1/channels and returns raw JSON.
83 func (c *Client) ListChannels() (json.RawMessage, error) {
84 return c.get("/v1/channels")
85 }
86
87 // ListLLMBackends sends GET /v1/llm/backends and returns raw JSON.
88 func (c *Client) ListLLMBackends() (json.RawMessage, error) {
89 return c.get("/v1/llm/backends")
90 }
91
92 // GetLLMBackend sends GET /v1/llm/backends and finds the named backend, returning raw JSON.
93 func (c *Client) GetLLMBackend(name string) (json.RawMessage, error) {
94 raw, err := c.get("/v1/llm/backends")
95 if err != nil {
96
--- cmd/scuttlectl/main.go
+++ cmd/scuttlectl/main.go
@@ -129,24 +129,29 @@
129129
fmt.Fprintf(os.Stderr, "unknown subcommand: channels %s\n", args[1])
130130
os.Exit(1)
131131
}
132132
case "backend", "backends":
133133
if len(args) < 2 {
134
- fmt.Fprintf(os.Stderr, "usage: scuttlectl backend rename <old-name> <new-name>\n")
134
+ fmt.Fprintf(os.Stderr, "usage: scuttlectl backend <list|get|delete|rename> [args]\n")
135135
os.Exit(1)
136136
}
137137
switch args[1] {
138
+ case "list":
139
+ cmdBackendList(api, *jsonFlag)
140
+ case "get":
141
+ requireArgs(args, 3, "scuttlectl backend get <name>")
142
+ cmdBackendGet(api, args[2], *jsonFlag)
143
+ case "delete", "rm":
144
+ requireArgs(args, 3, "scuttlectl backend delete <name>")
145
+ cmdBackendDelete(api, args[2])
138146
case "rename":
139147
requireArgs(args, 4, "scuttlectl backend rename <old-name> <new-name>")
140148
cmdBackendRename(api, args[2], args[3])
141149
default:
142150
fmt.Fprintf(os.Stderr, "unknown subcommand: backend %s\n", args[1])
143151
os.Exit(1)
144152
}
145
- case "logs":
146
- fmt.Fprintln(os.Stderr, "logs tail: not yet implemented (requires scribe HTTP endpoint)")
147
- os.Exit(1)
148153
default:
149154
fmt.Fprintf(os.Stderr, "unknown command: %s\n", args[0])
150155
usage()
151156
os.Exit(1)
152157
}
@@ -393,10 +398,65 @@
393398
394399
func cmdChannelDelete(api *apiclient.Client, channel string) {
395400
die(api.DeleteChannel(channel))
396401
fmt.Printf("Channel deleted: #%s\n", strings.TrimPrefix(channel, "#"))
397402
}
403
+
404
+func cmdBackendList(api *apiclient.Client, asJSON bool) {
405
+ raw, err := api.ListLLMBackends()
406
+ die(err)
407
+ if asJSON {
408
+ printJSON(raw)
409
+ return
410
+ }
411
+ var body struct {
412
+ Backends []struct {
413
+ Name string `json:"name"`
414
+ Provider string `json:"provider"`
415
+ } `json:"backends"`
416
+ }
417
+ must(json.Unmarshal(raw, &body))
418
+ if len(body.Backends) == 0 {
419
+ fmt.Println("no backends")
420
+ return
421
+ }
422
+ tw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
423
+ fmt.Fprintln(tw, "NAME\tPROVIDER")
424
+ for _, b := range body.Backends {
425
+ fmt.Fprintf(tw, "%s\t%s\n", b.Name, b.Provider)
426
+ }
427
+ tw.Flush()
428
+}
429
+
430
+func cmdBackendGet(api *apiclient.Client, name string, asJSON bool) {
431
+ raw, err := api.GetLLMBackend(name)
432
+ die(err)
433
+ if asJSON {
434
+ printJSON(raw)
435
+ return
436
+ }
437
+ var b struct {
438
+ Name string `json:"name"`
439
+ Provider string `json:"provider"`
440
+ Model string `json:"model"`
441
+ BaseURL string `json:"base_url,omitempty"`
442
+ }
443
+ must(json.Unmarshal(raw, &b))
444
+ tw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
445
+ fmt.Fprintf(tw, "name\t%s\n", b.Name)
446
+ fmt.Fprintf(tw, "provider\t%s\n", b.Provider)
447
+ fmt.Fprintf(tw, "model\t%s\n", b.Model)
448
+ if b.BaseURL != "" {
449
+ fmt.Fprintf(tw, "base_url\t%s\n", b.BaseURL)
450
+ }
451
+ tw.Flush()
452
+}
453
+
454
+func cmdBackendDelete(api *apiclient.Client, name string) {
455
+ die(api.DeleteLLMBackend(name))
456
+ fmt.Printf("Backend deleted: %s\n", name)
457
+}
398458
399459
func cmdBackendRename(api *apiclient.Client, oldName, newName string) {
400460
raw, err := api.GetLLMBackend(oldName)
401461
die(err)
402462
@@ -450,20 +510,22 @@
450510
setup [path] interactive wizard — write scuttlebot.yaml (no token needed)
451511
status daemon + ergo health
452512
agents list list all registered agents
453513
agent get <nick> get a single agent
454514
agent register <nick> register a new agent, print credentials
455
- [--type worker|orchestrator|observer]
515
+ [--type worker|orchestrator|observer|operator]
456516
[--channels #a,#b,#c]
457517
agent revoke <nick> revoke agent credentials
458518
agent delete <nick> permanently remove agent from registry
459519
agent rotate <nick> rotate agent password
460520
channels list list active channels
461521
channels users <channel> list users in a channel
462522
channels delete <channel> part bridge from channel (closes when empty)
463
- backend rename <old> <new> rename an LLM backend
464
- logs tail tail scribe log (coming soon)
523
+ backend list list LLM backends
524
+ backend get <name> show a single backend
525
+ backend delete <name> remove a backend
526
+ backend rename <old> <new> rename a backend
465527
admin list list admin accounts
466528
admin add <username> add admin (prompts for password)
467529
admin remove <username> remove admin
468530
admin passwd <username> change admin password (prompts)
469531
`, version)
470532
--- cmd/scuttlectl/main.go
+++ cmd/scuttlectl/main.go
@@ -129,24 +129,29 @@
129 fmt.Fprintf(os.Stderr, "unknown subcommand: channels %s\n", args[1])
130 os.Exit(1)
131 }
132 case "backend", "backends":
133 if len(args) < 2 {
134 fmt.Fprintf(os.Stderr, "usage: scuttlectl backend rename <old-name> <new-name>\n")
135 os.Exit(1)
136 }
137 switch args[1] {
 
 
 
 
 
 
 
 
138 case "rename":
139 requireArgs(args, 4, "scuttlectl backend rename <old-name> <new-name>")
140 cmdBackendRename(api, args[2], args[3])
141 default:
142 fmt.Fprintf(os.Stderr, "unknown subcommand: backend %s\n", args[1])
143 os.Exit(1)
144 }
145 case "logs":
146 fmt.Fprintln(os.Stderr, "logs tail: not yet implemented (requires scribe HTTP endpoint)")
147 os.Exit(1)
148 default:
149 fmt.Fprintf(os.Stderr, "unknown command: %s\n", args[0])
150 usage()
151 os.Exit(1)
152 }
@@ -393,10 +398,65 @@
393
394 func cmdChannelDelete(api *apiclient.Client, channel string) {
395 die(api.DeleteChannel(channel))
396 fmt.Printf("Channel deleted: #%s\n", strings.TrimPrefix(channel, "#"))
397 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
398
399 func cmdBackendRename(api *apiclient.Client, oldName, newName string) {
400 raw, err := api.GetLLMBackend(oldName)
401 die(err)
402
@@ -450,20 +510,22 @@
450 setup [path] interactive wizard — write scuttlebot.yaml (no token needed)
451 status daemon + ergo health
452 agents list list all registered agents
453 agent get <nick> get a single agent
454 agent register <nick> register a new agent, print credentials
455 [--type worker|orchestrator|observer]
456 [--channels #a,#b,#c]
457 agent revoke <nick> revoke agent credentials
458 agent delete <nick> permanently remove agent from registry
459 agent rotate <nick> rotate agent password
460 channels list list active channels
461 channels users <channel> list users in a channel
462 channels delete <channel> part bridge from channel (closes when empty)
463 backend rename <old> <new> rename an LLM backend
464 logs tail tail scribe log (coming soon)
 
 
465 admin list list admin accounts
466 admin add <username> add admin (prompts for password)
467 admin remove <username> remove admin
468 admin passwd <username> change admin password (prompts)
469 `, version)
470
--- cmd/scuttlectl/main.go
+++ cmd/scuttlectl/main.go
@@ -129,24 +129,29 @@
129 fmt.Fprintf(os.Stderr, "unknown subcommand: channels %s\n", args[1])
130 os.Exit(1)
131 }
132 case "backend", "backends":
133 if len(args) < 2 {
134 fmt.Fprintf(os.Stderr, "usage: scuttlectl backend <list|get|delete|rename> [args]\n")
135 os.Exit(1)
136 }
137 switch args[1] {
138 case "list":
139 cmdBackendList(api, *jsonFlag)
140 case "get":
141 requireArgs(args, 3, "scuttlectl backend get <name>")
142 cmdBackendGet(api, args[2], *jsonFlag)
143 case "delete", "rm":
144 requireArgs(args, 3, "scuttlectl backend delete <name>")
145 cmdBackendDelete(api, args[2])
146 case "rename":
147 requireArgs(args, 4, "scuttlectl backend rename <old-name> <new-name>")
148 cmdBackendRename(api, args[2], args[3])
149 default:
150 fmt.Fprintf(os.Stderr, "unknown subcommand: backend %s\n", args[1])
151 os.Exit(1)
152 }
 
 
 
153 default:
154 fmt.Fprintf(os.Stderr, "unknown command: %s\n", args[0])
155 usage()
156 os.Exit(1)
157 }
@@ -393,10 +398,65 @@
398
399 func cmdChannelDelete(api *apiclient.Client, channel string) {
400 die(api.DeleteChannel(channel))
401 fmt.Printf("Channel deleted: #%s\n", strings.TrimPrefix(channel, "#"))
402 }
403
404 func cmdBackendList(api *apiclient.Client, asJSON bool) {
405 raw, err := api.ListLLMBackends()
406 die(err)
407 if asJSON {
408 printJSON(raw)
409 return
410 }
411 var body struct {
412 Backends []struct {
413 Name string `json:"name"`
414 Provider string `json:"provider"`
415 } `json:"backends"`
416 }
417 must(json.Unmarshal(raw, &body))
418 if len(body.Backends) == 0 {
419 fmt.Println("no backends")
420 return
421 }
422 tw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
423 fmt.Fprintln(tw, "NAME\tPROVIDER")
424 for _, b := range body.Backends {
425 fmt.Fprintf(tw, "%s\t%s\n", b.Name, b.Provider)
426 }
427 tw.Flush()
428 }
429
430 func cmdBackendGet(api *apiclient.Client, name string, asJSON bool) {
431 raw, err := api.GetLLMBackend(name)
432 die(err)
433 if asJSON {
434 printJSON(raw)
435 return
436 }
437 var b struct {
438 Name string `json:"name"`
439 Provider string `json:"provider"`
440 Model string `json:"model"`
441 BaseURL string `json:"base_url,omitempty"`
442 }
443 must(json.Unmarshal(raw, &b))
444 tw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
445 fmt.Fprintf(tw, "name\t%s\n", b.Name)
446 fmt.Fprintf(tw, "provider\t%s\n", b.Provider)
447 fmt.Fprintf(tw, "model\t%s\n", b.Model)
448 if b.BaseURL != "" {
449 fmt.Fprintf(tw, "base_url\t%s\n", b.BaseURL)
450 }
451 tw.Flush()
452 }
453
454 func cmdBackendDelete(api *apiclient.Client, name string) {
455 die(api.DeleteLLMBackend(name))
456 fmt.Printf("Backend deleted: %s\n", name)
457 }
458
459 func cmdBackendRename(api *apiclient.Client, oldName, newName string) {
460 raw, err := api.GetLLMBackend(oldName)
461 die(err)
462
@@ -450,20 +510,22 @@
510 setup [path] interactive wizard — write scuttlebot.yaml (no token needed)
511 status daemon + ergo health
512 agents list list all registered agents
513 agent get <nick> get a single agent
514 agent register <nick> register a new agent, print credentials
515 [--type worker|orchestrator|observer|operator]
516 [--channels #a,#b,#c]
517 agent revoke <nick> revoke agent credentials
518 agent delete <nick> permanently remove agent from registry
519 agent rotate <nick> rotate agent password
520 channels list list active channels
521 channels users <channel> list users in a channel
522 channels delete <channel> part bridge from channel (closes when empty)
523 backend list list LLM backends
524 backend get <name> show a single backend
525 backend delete <name> remove a backend
526 backend rename <old> <new> rename a backend
527 admin list list admin accounts
528 admin add <username> add admin (prompts for password)
529 admin remove <username> remove admin
530 admin passwd <username> change admin password (prompts)
531 `, version)
532

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button