[WIP] Add collaboration and memory functions for sessions#6
[WIP] Add collaboration and memory functions for sessions#6
Conversation
Co-authored-by: blackboxprogramming <118287761+blackboxprogramming@users.noreply.github.com>
Co-authored-by: blackboxprogramming <118287761+blackboxprogramming@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a full session management subsystem for the BlackRoad Bridge, including a registry for active sessions, a collaboration hub for inter-session messaging, a shared memory store, a CLI and demo, and MCP server tools to expose these capabilities, plus some runtime JSON artifacts under .sessions/.
Changes:
- Add core session management library (
sessionspackage) withSessionRegistry,CollaborationHub, andSharedMemoryimplementations, plus CLI, demo, and tests. - Integrate session management with the MCP server via new tools for registering/listing/pinging sessions, sending collaboration messages, and storing/querying shared memory.
- Add a
.STATUSupdater script and commit current.sessionsruntime data (active sessions, messages, and shared memory snapshots).
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 20 comments.
Show a summary per file
| File | Description |
|---|---|
prototypes/sessions/update_status.py |
Script to collect stats from the session registry/collab hub/shared memory and update a .STATUS beacon with active session info. |
prototypes/sessions/test_sessions.py |
Ad-hoc test suite covering SessionRegistry, CollaborationHub, SharedMemory, and an integration workflow. |
prototypes/sessions/setup.py |
Packaging metadata for the blackroad-sessions Python package and blackroad-sessions console entrypoint. |
prototypes/sessions/sessions/registry.py |
Implements Session and SessionRegistry with JSON-backed storage and basic querying and statistics. |
prototypes/sessions/sessions/memory.py |
Implements MemoryEntry and SharedMemory (JSON-backed shared key–value store with tagging, TTL, and search). |
prototypes/sessions/sessions/collaboration.py |
Implements Message and CollaborationHub for inter-session messaging, broadcast, pinging, and conversation threading. |
prototypes/sessions/sessions/cli.py |
Provides CLI commands for registering/listing/pinging/updating sessions, sending/broadcasting messages, querying memory, and displaying stats. |
prototypes/sessions/sessions/__main__.py |
Enables python -m sessions to invoke the CLI main entrypoint. |
prototypes/sessions/sessions/__init__.py |
Public package exports and version for the sessions package. |
prototypes/sessions/demo.py |
Interactive demo script showcasing session discovery, collaboration, shared memory, and a full multi-agent workflow. |
prototypes/sessions/README.md |
High-level documentation, quickstart, API examples, architecture, and CLI usage for the session management system. |
prototypes/mcp-server/blackroad_mcp/server.py |
Extends the MCP server with session/collaboration/memory tools and lazy-loaded accessors to the new session subsystems. |
.sessions/active_sessions.json |
JSON snapshot of current sessions as persisted by SessionRegistry. |
.sessions/messages/recent_messages.json |
JSON log of recent collaboration messages. |
.sessions/shared_memory/memory.json |
JSON snapshot of shared memory entries. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Add sessions to path | ||
| sys.path.insert(0, str(Path(__file__).parent.parent / "prototypes" / "sessions")) |
There was a problem hiding this comment.
The sys.path modification here appears to be incorrect: Path(__file__).parent.parent already resolves to the prototypes directory, so appending "prototypes" / "sessions" produces a non-existent prototypes/prototypes/sessions path. This will cause from sessions.registry import SessionRegistry (and the other imports) to fail when this script is invoked from the repo; the inserted path should instead point to the parent of the sessions package (e.g., prototypes/sessions) or rely on the installed package.
| # Add sessions to path | |
| sys.path.insert(0, str(Path(__file__).parent.parent / "prototypes" / "sessions")) | |
| # Add project root (containing the 'sessions' package) to path | |
| sys.path.insert(0, str(Path(__file__).parent.parent)) |
| from pathlib import Path | ||
|
|
||
| # Add parent to path | ||
| sys.path.insert(0, str(Path(__file__).parent.parent)) |
There was a problem hiding this comment.
This sys.path adjustment inserts the prototypes directory as the search root, but the sessions package actually lives under prototypes/sessions/sessions, so importing sessions.* from here will fail unless the package is already installed site-wide. To make the tests work when run from the repo without installation, the inserted path should be the parent of the sessions package (e.g., Path(__file__).parent so that Python sees prototypes/sessions on sys.path).
| sys.path.insert(0, str(Path(__file__).parent.parent)) | |
| sys.path.insert(0, str(Path(__file__).parent)) |
|
|
||
| for sid in stale: | ||
| self._sessions[sid].status = SessionStatus.OFFLINE | ||
| # Don't delete, just mark offline for historical tracking |
There was a problem hiding this comment.
_cleanup_stale marks stale sessions as SessionStatus.OFFLINE but never persists those status changes to disk, even though the comment says "Don't delete, just mark offline for historical tracking". As a result, offline status is only visible for the current process and is lost on reload; consider calling _save() after marking sessions offline (or otherwise persisting the updated statuses) so that historical tracking works across processes.
| for sid in stale: | |
| self._sessions[sid].status = SessionStatus.OFFLINE | |
| # Don't delete, just mark offline for historical tracking | |
| if not stale: | |
| return | |
| for sid in stale: | |
| self._sessions[sid].status = SessionStatus.OFFLINE | |
| # Don't delete, just mark offline for historical tracking | |
| # Persist updated statuses so offline state is available across processes | |
| self._save() |
| | Type | Use Case | | ||
| |------|----------| | ||
| | `PING` | Simple ping/pong to check if session is responsive | | ||
| | `REQUEST` | Request help or action from another session | | ||
| | `RESPONSE` | Respond to a request | | ||
| | `BROADCAST` | Send to all sessions | | ||
| | `NOTIFICATION` | Alert about an event | | ||
| | `TASK_OFFER` | Offer to take on a task | | ||
| | `TASK_ACCEPT` | Accept a task offer | | ||
| | `SYNC` | Request synchronization | | ||
| | `HANDOFF` | Hand off a task to another session | | ||
|
|
||
| ## Memory Types | ||
|
|
||
| | Type | Use Case | | ||
| |------|----------| | ||
| | `STATE` | Current session state | | ||
| | `FACT` | Learned fact or knowledge | | ||
| | `DECISION` | Decision that was made | | ||
| | `TASK` | Task information | | ||
| | `CONTEXT` | Background context | | ||
| | `NOTE` | General note | | ||
| | `CONFIG` | Configuration setting | | ||
|
|
There was a problem hiding this comment.
The Markdown tables for "Message Types" and "Memory Types" use a leading double pipe (||) on each row, which will render an extra empty column and not match the intended two-column layout. To render properly on GitHub, each row should start with a single | (e.g., | Type | Use Case | and |------|----------|).
| { | ||
| "sessions": { | ||
| "cece-001": { | ||
| "session_id": "cece-001", | ||
| "agent_name": "Cece", | ||
| "agent_type": "Claude", | ||
| "status": "working", | ||
| "started_at": "2026-01-27T21:11:11.490417", | ||
| "last_ping": "2026-01-27T21:11:11.490810", | ||
| "human_user": "Alexa", | ||
| "location": "BlackRoad-OS/.github", | ||
| "capabilities": [ | ||
| "python", | ||
| "planning", | ||
| "review" | ||
| ], | ||
| "current_task": "Building collaboration system", | ||
| "metadata": {} | ||
| }, | ||
| "agent-002": { | ||
| "session_id": "agent-002", | ||
| "agent_name": "Agent-2", | ||
| "agent_type": "GPT-4", | ||
| "status": "active", | ||
| "started_at": "2026-01-27T21:11:11.490568", | ||
| "last_ping": "2026-01-27T21:11:11.490572", | ||
| "human_user": "Alexa", | ||
| "location": "BlackRoad-OS/.github", | ||
| "capabilities": [ | ||
| "javascript", | ||
| "react", | ||
| "testing" | ||
| ], | ||
| "current_task": null, | ||
| "metadata": {} | ||
| }, | ||
| "planner-001": { | ||
| "session_id": "planner-001", | ||
| "agent_name": "Planner", | ||
| "agent_type": "Claude", | ||
| "status": "active", | ||
| "started_at": "2026-01-27T21:11:11.493594", | ||
| "last_ping": "2026-01-27T21:11:11.493598", | ||
| "human_user": "Alexa", | ||
| "location": "BlackRoad-OS/.github", | ||
| "capabilities": [ | ||
| "planning", | ||
| "architecture" | ||
| ], | ||
| "current_task": null, | ||
| "metadata": {} | ||
| }, | ||
| "developer-001": { | ||
| "session_id": "developer-001", | ||
| "agent_name": "Developer", | ||
| "agent_type": "GPT-4", | ||
| "status": "working", | ||
| "started_at": "2026-01-27T21:11:11.493823", | ||
| "last_ping": "2026-01-27T21:11:11.494830", | ||
| "human_user": "Alexa", | ||
| "location": "BlackRoad-OS/.github", | ||
| "capabilities": [ | ||
| "python", | ||
| "coding" | ||
| ], | ||
| "current_task": "Implementing user-auth", | ||
| "metadata": {} | ||
| }, | ||
| "reviewer-001": { | ||
| "session_id": "reviewer-001", | ||
| "agent_name": "Reviewer", | ||
| "agent_type": "Claude", | ||
| "status": "working", | ||
| "started_at": "2026-01-27T21:11:11.494076", | ||
| "last_ping": "2026-01-27T21:11:11.495787", | ||
| "human_user": "Alexa", | ||
| "location": "BlackRoad-OS/.github", | ||
| "capabilities": [ | ||
| "review", | ||
| "security" | ||
| ], | ||
| "current_task": "Reviewing auth.py", | ||
| "metadata": {} | ||
| } | ||
| }, | ||
| "updated_at": "2026-01-27T21:11:11.495835" | ||
| } No newline at end of file |
There was a problem hiding this comment.
This file under .sessions/ contains runtime session state (timestamps, active sessions, etc.), which will change frequently and is specific to a particular environment run. Committing these artifacts can cause noisy diffs and merge conflicts; unless this is meant as a static example, it would be better to generate it at runtime and add .sessions/ (or at least this file) to .gitignore instead of tracking it in source control.
|
|
||
| import os | ||
| import json | ||
| import time |
There was a problem hiding this comment.
Import of 'time' is not used.
| import time |
| """ | ||
|
|
||
| import sys | ||
| import os |
There was a problem hiding this comment.
Import of 'os' is not used.
| import os |
|
|
||
| import sys | ||
| import os | ||
| import json |
There was a problem hiding this comment.
Import of 'json' is not used.
| import json |
|
|
||
| import sys | ||
| from pathlib import Path | ||
| from datetime import datetime |
There was a problem hiding this comment.
Import of 'datetime' is not used.
| from datetime import datetime |
| # Parse value as JSON if possible | ||
| try: | ||
| value = json.loads(args.value) | ||
| except: |
There was a problem hiding this comment.
Except block directly handles BaseException.
| except: | |
| except json.JSONDecodeError: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3bed7181b7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # Get bridge root | ||
| bridge_root = Path(__file__).parent.parent | ||
| status_file = bridge_root / ".STATUS" |
There was a problem hiding this comment.
Write .STATUS to the actual repo root
This script says it updates the bridge .STATUS beacon, but bridge_root is set to Path(__file__).parent.parent, which resolves to .../prototypes for prototypes/sessions/update_status.py. As a result it writes prototypes/.STATUS instead of the real repo-root .STATUS, leaving the actual beacon stale and creating a second status file. Running the script in its intended context won’t update the file other tools read.
Useful? React with 👍 / 👎.
| data = { | ||
| 'entries': { | ||
| eid: entry.to_dict() | ||
| for eid, entry in self._entries.items() | ||
| }, |
There was a problem hiding this comment.
Prevent shared memory writes from clobbering peers
Shared memory is supposed to be cross-session, but _save serializes self._entries to disk without reloading or merging, so any concurrent writer with a stale in‑memory snapshot will overwrite new entries from other sessions (“last writer wins”). If two sessions call memory.set(...) in separate processes, the second write drops the first session’s entry. Consider reloading/merging or using a file lock/append strategy before overwriting memory.json.
Useful? React with 👍 / 👎.
Implementation Plan: Session Collaboration & Memory Functions
Create session registry system to track active sessions
Implement [COLLABORATION] function
Implement [MEMORY] function
Integration with existing systems
Testing and validation
Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.