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: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ src/agent_event_bus/
├── storage.py # SQLite backend (Session, Event, SQLiteStorage)
├── helpers.py # Notifications, repo extraction
├── middleware.py # Request logging → ~/.claude/contrib/agent-event-bus/agent-event-bus.log
├── session_ids.py # Docker-style display_id generation
├── session_ids.py # Dinosaur-themed display_id generation
├── cli.py # CLI wrapper for shell scripts
└── guide.md # Usage guide (agent-event-bus://guide resource)
```
Expand Down Expand Up @@ -143,7 +143,7 @@ CLI and MCP expose the same functionality:
- **Session cleanup**: 24-hour timeout + PID liveness checks for local sessions
- **Auto-heartbeat**: `publish_event` and `get_events` refresh heartbeat
- **Cursor auto-tracking**: `get_events(session_id=X)` persists cursor; `resume=True` uses it
- **UUID session IDs**: `session_id` is UUID; `display_id` is human-readable ("brave-tiger")
- **UUID session IDs**: `session_id` is UUID; `display_id` is human-readable ("brave-trex")
- **Client deduplication**: `(machine, client_id)` enables session resumption

## Operations
Expand Down
2 changes: 1 addition & 1 deletion docs/EXAMPLE_COMMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Pagination: pass `next_cursor` as `cursor` in the next call. Empty `events` arra

### Session format (`list_sessions`)

Sessions self-register with a name, machine, and optional `client_id` for resumption. The server assigns a `display_id` (Docker-style codename) and infers `repo` from the working directory.
Sessions self-register with a name, machine, and optional `client_id` for resumption. The server assigns a `display_id` (dinosaur-themed codename) and infers `repo` from the working directory.

```json
{
Expand Down
4 changes: 2 additions & 2 deletions src/agent_event_bus/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ CC sessions (e.g., in separate terminals or worktrees), this MCP server lets ses
### 1. Register on startup
```
register_session(name="auth-feature", client_id="cc-session-abc")
→ {session_id: "cc-session-abc", display_id: "brave-tiger", cursor: "42", ...}
→ {session_id: "cc-session-abc", display_id: "brave-trex", cursor: "42", ...}
```
- `session_id` is your unique identifier (your `client_id`, or a UUID if not provided)
- `display_id` is human-readable ("brave-tiger") - for display only
- `display_id` is human-readable ("brave-trex") - for display only
- Use `session_id` for all API calls

### 2. Poll for events
Expand Down
12 changes: 6 additions & 6 deletions src/agent_event_bus/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def _lookup_session_display_id(session_id: str) -> str | None:
"""Look up human-readable display_id from a session_id.

Session IDs are now UUIDs (or client_ids). This resolves them to
human-readable display names like "brave-tiger".
human-readable display names like "brave-trex".

Returns the display_id if found, None otherwise.
"""
Expand All @@ -43,7 +43,7 @@ def _get_active_sessions_map() -> dict[str, str]:
"""Get mapping of session_id → display_id for active sessions.

Returns a dict where keys are session IDs (UUIDs) and values are
human-readable display_ids (like "brave-tiger").
human-readable display_ids (like "brave-trex").
"""
try:
storage = _get_storage()
Expand Down Expand Up @@ -75,9 +75,9 @@ def _get_active_sessions_map() -> dict[str, str]:


def _is_human_readable_id(session_id: str) -> bool:
"""Check if a session ID is human-readable (Docker-style adjective-noun).
"""Check if a session ID is human-readable (adjective-dinosaur format).

Human-readable: "brave-tiger", "tender-hawk" (two lowercase words with hyphen)
Human-readable: "brave-trex", "tender-raptor" (two lowercase words with hyphen)
Not human-readable: "b712a0ba-1ee6-4c18-a647-31a785147665" (UUID)
"""
if not session_id or session_id == "anonymous":
Expand All @@ -92,7 +92,7 @@ def _is_human_readable_id(session_id: str) -> bool:
def _format_session_id_value(session_id: str) -> str:
"""Format a session_id value for display.

Human-readable IDs (brave-tiger) are shown prominently.
Human-readable IDs (brave-trex) are shown prominently.
UUIDs/hex strings are dimmed and truncated.
"""
if _is_human_readable_id(session_id):
Expand Down Expand Up @@ -138,7 +138,7 @@ def _format_list(items: list) -> str:
first = items[0] if isinstance(items[0], dict) else None
if first:
if "session_id" in first:
# Show session display_ids (human-readable names): tender-hawk, brave-tiger, ...
# Show session display_ids (human-readable names): tender-raptor, brave-trex, ...
# Prefer display_id if available, look it up if not, format UUID as fallback
names = []
for item in items:
Expand Down
110 changes: 55 additions & 55 deletions src/agent_event_bus/session_ids.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""Human-readable session ID generation (Docker-style names)."""
"""Human-readable session ID generation (dinosaur-themed names)."""

import random

# Word lists for human-readable session IDs
# ~50 adjectives x ~50 animals = ~2500 unique combinations
# ~50 adjectives x ~50 dinosaurs = ~2500 unique combinations
ADJECTIVES = [
"brave",
"calm",
Expand Down Expand Up @@ -57,60 +57,60 @@
"rustic",
]

ANIMALS = [
"badger",
"cat",
"dog",
"eagle",
"falcon",
"gopher",
"heron",
"ibis",
"jaguar",
"koala",
"lemur",
"moose",
"newt",
"otter",
"panda",
"quail",
"rabbit",
"salmon",
"tiger",
"urchin",
"viper",
"walrus",
"yak",
"zebra",
"bear",
"crane",
"duck",
"fox",
"goose",
"hawk",
"iguana",
"jay",
"alpaca",
"bison",
"coyote",
"dingo",
"ferret",
"gecko",
"hyena",
"impala",
"jackal",
"kiwi",
"llama",
"marmot",
"narwhal",
"osprey",
"parrot",
"raven",
"sloth",
"toucan",
DINOSAURS = [
"trex",
"raptor",
"stego",
"bronto",
"tricera",
"ankylo",
"diplo",
"allo",
"ptero",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Important] guide.md still uses "brave-tiger" as the example display ID (lines 34 and 37), and CLAUDE.md references "brave-tiger" (line 146) and calls this "Docker-style display_id generation" (line 83). These should be updated to reflect the new dinosaur theme (e.g., "brave-trex") for consistency. Per CLAUDE.md: "When modifying API: Update CLI help, MCP docstrings, and guide.md together."

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Important] The previous review flagged this and it remains unaddressed: many files still reference "brave-tiger" and "Docker-style" terminology. Files that need updating:

  • CLAUDE.md (lines 83, 146) — references "Docker-style" and "brave-tiger"
  • src/agent_event_bus/guide.md (lines 34, 37) — example display IDs
  • src/agent_event_bus/middleware.py (lines 30, 46, 78, 80, 95, 141) — comments and docstrings
  • src/agent_event_bus/storage.py (lines 49, 55, 147) — comments
  • docs/EXAMPLE_COMMS.md (line 45) — "Docker-style codename"
  • Various test files (test_middleware.py, test_storage.py) — test data using "brave-tiger"

Per CLAUDE.md: "When modifying API: Update CLI help, MCP docstrings, and guide.md together." At minimum, update guide.md, CLAUDE.md, and source-code docstrings/comments to reflect the dinosaur theme. Test data strings like "brave-tiger" are less critical since they're just arbitrary test values, but the documentation and comments should be consistent.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Important] This is the third review flagging this: documentation and source comments across the repo still reference "brave-tiger" and "Docker-style" terminology. The PR's own CLAUDE.md says "When modifying API: Update CLI help, MCP docstrings, and guide.md together."

Files that need updating (at minimum the non-test files):

  • CLAUDE.md (lines 83, 146) — "Docker-style display_id generation" and "brave-tiger"
  • src/agent_event_bus/guide.md (lines 34, 37) — example display IDs
  • src/agent_event_bus/middleware.py (lines 30, 46, 78, 80, 95, 141) — comments/docstrings referencing "brave-tiger" and "Docker-style"
  • src/agent_event_bus/storage.py (lines 49, 55, 147) — comments referencing "brave-tiger"
  • docs/EXAMPLE_COMMS.md (line 45) — "Docker-style codename"

Test files (test_middleware.py, test_storage.py) use "brave-tiger" as arbitrary test data — less critical, but worth updating for consistency.

"plesio",
"spino",
"carno",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] Some of these abbreviated names are pretty opaque — citipa, lambe, nodo, acro may not be immediately recognizable as dinosaurs. Consider using slightly longer forms where the short form isn't well-known (e.g., citipati, lambeosaur, nodosaur). Not blocking, just a readability thought.

"iguano",
"hadro",
"cerato",
"compsy",
"dilo",
"galli",
"thero",
"baryon",
"deinon",
"styra",
"pachy",
"corytho",
"parasaur",
"maia",
"oviraptor",
"draco",
"kentro",
"camara",
"titano",
"megalo",
"archeo",
"coelo",
"micro",
"proto",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] Some abbreviated dinosaur names are quite opaque — e.g., citipa, lambe, nodo, acro, bary, compso may not be immediately recognizable as dinosaurs to most people. Consider using slightly longer forms where the abbreviation isn't well-known (e.g., citipati, nodosaur, lambeosaur). Not blocking — just a readability/fun-factor thought (this was also noted in the prior review).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] Repeated from prior reviews: some abbreviated names are quite opaque — citipa, lambe, nodo, acro, bary, compso won't be recognizable as dinosaurs to most people. Consider slightly longer forms for the least obvious ones (e.g., citipati, nodosaur, lambeosaur). Not blocking — just a readability/fun-factor thought.

"sino",
"yuty",
"theri",
"tarbos",
"acrocanth",
"giganto",
"amarga",
"citipati",
"edmonto",
"lambeo",
"nodosaur",
"ourano",
"suchomi",
"utah",
]


def generate_session_id() -> str:
"""Generate a human-readable session ID like 'brave-tiger'."""
return f"{random.choice(ADJECTIVES)}-{random.choice(ANIMALS)}"
"""Generate a dinosaur-themed session ID like 'brave-trex'."""
return f"{random.choice(ADJECTIVES)}-{random.choice(DINOSAURS)}"
6 changes: 3 additions & 3 deletions src/agent_event_bus/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ def migrate_v2(conn: sqlite3.Connection) -> None:
"""Add display_id and deleted_at columns to sessions table.

This migration:
1. Adds display_id column (human-readable name like "brave-tiger")
1. Adds display_id column (human-readable name like "brave-trex")
2. Adds deleted_at column (for soft-delete)
3. Copies existing id → display_id
4. Changes id to use client_id (if available) or generates UUID

Note on historical data: Existing events retain their old session_id references
(human-readable names like "brave-tiger"). These become orphaned - they no longer
(human-readable names like "brave-trex"). These become orphaned - they no longer
match any session's primary key. This is expected: the middleware handles display
of historical events via _is_human_readable_id() fallback. New events will use
the new UUID-based session_id.
Expand Down Expand Up @@ -144,7 +144,7 @@ class Session:
"""Represents an active Claude Code session."""

id: str # UUID or client_id (stable identifier for API use)
display_id: str # Human-readable name like "brave-tiger" (for display only)
display_id: str # Human-readable name like "brave-trex" (for display only)
name: str
machine: str
cwd: str
Expand Down
16 changes: 8 additions & 8 deletions tests/test_session_ids.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Tests for session_ids module (Docker-style display ID generation)."""
"""Tests for session_ids module (dinosaur-themed display ID generation)."""

from agent_event_bus.middleware import _is_human_readable_id
from agent_event_bus.session_ids import ADJECTIVES, ANIMALS, generate_session_id
from agent_event_bus.session_ids import ADJECTIVES, DINOSAURS, generate_session_id


class TestGenerateSessionId:
Expand All @@ -21,11 +21,11 @@ def test_passes_human_readable_check(self):
assert _is_human_readable_id(session_id), f"ID failed check: {session_id}"

def test_uses_words_from_lists(self):
"""Generated ID uses words from ADJECTIVES and ANIMALS lists."""
"""Generated ID uses words from ADJECTIVES and DINOSAURS lists."""
session_id = generate_session_id()
adjective, animal = session_id.split("-")
adjective, dinosaur = session_id.split("-")
assert adjective in ADJECTIVES, f"Adjective not in list: {adjective}"
assert animal in ANIMALS, f"Animal not in list: {animal}"
assert dinosaur in DINOSAURS, f"Dinosaur not in list: {dinosaur}"

def test_randomness(self):
"""Multiple calls produce different results (with high probability)."""
Expand All @@ -37,11 +37,11 @@ def test_randomness(self):
def test_word_lists_non_empty(self):
"""Word lists have sufficient entries for good randomness."""
assert len(ADJECTIVES) >= 10, "ADJECTIVES list too small"
assert len(ANIMALS) >= 10, "ANIMALS list too small"
assert len(DINOSAURS) >= 10, "DINOSAURS list too small"

def test_word_lists_lowercase(self):
"""All words in lists are lowercase alphabetic."""
for word in ADJECTIVES:
assert word.isalpha() and word.islower(), f"Invalid adjective: {word}"
for word in ANIMALS:
assert word.isalpha() and word.islower(), f"Invalid animal: {word}"
for word in DINOSAURS:
assert word.isalpha() and word.islower(), f"Invalid dinosaur: {word}"
Loading