Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ fi
When `AGORA_URL` is set, the skill tells agents to post progress, questions,
blockers, verification results, and final handoffs to Agora.

The server-backed CLI commands `agora post`, `agora inbox`, and `agora status`
require `AGORA_URL` and fail when it is missing. `agora session` does not
contact the server and does not require `AGORA_URL`.

Run `agora session` once when each coding-agent session starts. The generated
`AGORA_THREAD` keeps that session's posts together while replies still inherit
their parent post's thread.
Expand Down
20 changes: 10 additions & 10 deletions internal/agoracli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ func runPost(ctx context.Context, args []string, cfg Config) int {
if strings.TrimSpace(*title) == "" {
return usageError(fs, "--title is required")
}
if skipIfNoServer(cfg) {
return 0
if code := requireServerURL("agora post", cfg); code != -1 {
return code
}

threadValue := thread.value
Expand Down Expand Up @@ -203,8 +203,8 @@ func runInbox(ctx context.Context, args []string, cfg Config) int {
if strings.TrimSpace(*agent) == "" {
return usageError(fs, "--agent is required")
}
if skipIfNoServer(cfg) {
return 0
if code := requireServerURL("agora inbox", cfg); code != -1 {
return code
}

query := url.Values{"limit": {fmt.Sprint(*limit)}}
Expand Down Expand Up @@ -252,8 +252,8 @@ func runStatus(ctx context.Context, args []string, cfg Config) int {
if !statuses[status] {
return usageError(fs, "unknown status %q", status)
}
if skipIfNoServer(cfg) {
return 0
if code := requireServerURL("agora status", cfg); code != -1 {
return code
}

payload := map[string]any{"actor": *actor, "status": status}
Expand Down Expand Up @@ -289,12 +289,12 @@ func usageError(fs *flag.FlagSet, format string, args ...any) int {
return 2
}

func skipIfNoServer(cfg Config) bool {
func requireServerURL(command string, cfg Config) int {
if strings.TrimSpace(cfg.BaseURL) != "" {
return false
return -1
}
fmt.Fprintln(cfg.stderr(), "AGORA_URL is not set; skipping Agora.")
return true
fmt.Fprintf(cfg.stderr(), "%s: AGORA_URL is required\n", command)
return 1
}

func printUsage(w io.Writer) {
Expand Down
55 changes: 41 additions & 14 deletions internal/agoracli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,21 +302,48 @@ func TestStatusUpdatesEvent(t *testing.T) {
}
}

func TestMissingURLSkipsRequest(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
code := Run(context.Background(), []string{"post", "--type", "summary", "--title", "Started task"}, Config{
Stdout: &stdout,
Stderr: &stderr,
})
if code != 0 {
t.Fatalf("exit code = %d, stderr = %s", code, stderr.String())
}
if stdout.String() != "" {
t.Fatalf("stdout = %q, want empty", stdout.String())
func TestMissingURLFailsForServerCommands(t *testing.T) {
tests := []struct {
name string
args []string
command string
}{
{
name: "post",
args: []string{"post", "--type", "summary", "--title", "Started task"},
command: "agora post",
},
{
name: "inbox",
args: []string{"inbox", "--agent", "codex"},
command: "agora inbox",
},
{
name: "status",
args: []string{"status", "evt-1", "acknowledged"},
command: "agora status",
},
}
if got := stderr.String(); got != "AGORA_URL is not set; skipping Agora.\n" {
t.Fatalf("stderr = %q", got)

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
code := Run(context.Background(), tt.args, Config{
Stdout: &stdout,
Stderr: &stderr,
})
if code != 1 {
t.Fatalf("exit code = %d, stderr = %s", code, stderr.String())
}
if stdout.String() != "" {
t.Fatalf("stdout = %q, want empty", stdout.String())
}
want := tt.command + ": AGORA_URL is required\n"
if got := stderr.String(); got != want {
t.Fatalf("stderr = %q, want %q", got, want)
}
})
}
}

Expand Down
2 changes: 2 additions & 0 deletions skills/agora-reporting/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ description: Report coding-agent progress, questions, decisions, blockers, tests

Use Agora as the shared coordination feed for human and agent work. If
`AGORA_URL` is unset, skip Agora reporting without blocking the task.
The server-backed commands `post`, `inbox`, and `status` require `AGORA_URL`;
`session` does not contact the server and does not require `AGORA_URL`.

## Setup

Expand Down
Loading