v0.1.0 - A vibe-coded MCP server for AI agents who need to learn to share
"Too many coders, one codebase" - The eternal struggle, now with 100% more AI
An MCP (Model Context Protocol) server that provides edit-awareness and intent coordination for coding agents using Yjs. Built with vibes, for vibes, by vibes.
Look, we get it. You've got Claude over here trying to refactor UserService.authenticate(), and Claude's cousin is simultaneously adding OAuth to the same function. Chaos ensues. Merge conflicts rain from the sky. Your git history looks like a crime scene.
SASP is here to teach these AI agents some manners. Think of it as a really passive-aggressive "OCCUPIED" sign for your code, but with more CRDTs and less bathroom humor.
SASP enables multiple AI coding agents to coordinate their edits in real-time by:
- 📢 Broadcasting awareness states - "Hey everyone, I'm editing UserService.authenticate, don't @ me"
- 🎫 Declaring edit intents - Reserve your scope like a beach towel on a hotel chair
- 🚨 Detecting overlaps - "Excuse me, I called dibs on that function"
- 📝 Recording summaries - Document your chaos for posterity
- 🎸 Keeping Git real - Because at the end of the day, Git is still the source of truth
- Real-time Awareness: Agents broadcast their current activity, file, selection, and rationale
- Intent Management: Reserve edit scopes with TTL-based leases
- Overlap Detection: Automatic detection of conflicting edits (symbol > range precedence)
- Edit Summaries: Track what changed, which tests ran, and outcomes
- MCP Integration: Full support for MCP tools, resources, and prompts
- Yjs-backed: Leverages Yjs for CRDT-based state synchronization
┌─────────────────────────────────────────────────────────┐
│ MCP Server (stdio) │
├─────────────────────────────────────────────────────────┤
│ Tools: │
│ - awareness.set_local │
│ - intent.start / update / end │
│ - edits.append_summary │
│ - git.commit (stub) │
├─────────────────────────────────────────────────────────┤
│ Resources: │
│ - resources.awareness.doc (snapshot) │
├─────────────────────────────────────────────────────────┤
│ Prompts: │
│ - plan-change │
│ - apply-diff │
│ - negotiate-overlap │
├─────────────────────────────────────────────────────────┤
│ Core Components: │
│ - Yjs Document (intents, summaries, awareness) │
│ - Overlap Detector (symbol > range precedence) │
│ - TTL Manager (intent expiration) │
│ - Auth Validator (bearer token + session) │
└─────────────────────────────────────────────────────────┘
# Install dependencies
npm install
# Build the project
npm run build
# Run tests
npm test
# Run demo
npm run demo# Via npm
npm start
# Or directly with node
node dist/index.jsThe server runs on stdio and can be integrated with any MCP-compatible host.
Set environment variables to configure the server:
# Authentication token (required)
export SASP_AUTH_TOKEN="your-secret-token"
# Room ID for Yjs sync (optional)
export SASP_ROOM_ID="my-team-room"
# Log level (optional)
export SASP_LOG_LEVEL="info" # debug | info | warn | errorAdd to your VS Code settings:
{
"mcp.servers": {
"sasp": {
"command": "node",
"args": ["/path/to/sasp/dist/index.js"],
"env": {
"SASP_AUTH_TOKEN": "your-secret-token"
}
}
}
}Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"sasp": {
"command": "node",
"args": ["/path/to/sasp/dist/index.js"],
"env": {
"SASP_AUTH_TOKEN": "your-secret-token"
}
}
}
}Set your agent's awareness state to broadcast what you're doing:
// Tool: awareness.set_local
{
"agent_id": "agent-alpha",
"session_id": "session-001",
"token": "your-secret-token",
"state": {
"agent_id": "agent-alpha",
"session_id": "session-001",
"activity": "editing", // planning | editing | testing | idle
"file": "src/UserService.ts",
"selection": { "symbol": "UserService.authenticate" },
"rationale": "Adding OAuth support",
"task_id": "TASK-123"
}
}Reserve a scope before editing:
// Tool: intent.start
{
"agent_id": "agent-alpha",
"session_id": "session-001",
"token": "your-secret-token",
"file": "src/UserService.ts",
"scope": {
"symbol": "UserService.authenticate" // or "range": { startLine: 10, endLine: 20 }
},
"reason": "Adding OAuth support",
"planned_delta_hash": "sha256-abc123",
"ttl_ms": 300000 // 5 minutes (optional)
}
// Response:
{
"ok": true,
"lease_id": "uuid-lease-id"
}
// Or if overlap detected:
{
"ok": false,
"error": "Intent overlaps with existing active intent",
"conflict": {
"conflicting_lease_id": "other-lease-id",
"reason": "Symbol 'UserService.authenticate' is already being edited by agent-beta"
}
}Modify scope, reason, or extend TTL:
// Tool: intent.update
{
"agent_id": "agent-alpha",
"session_id": "session-001",
"token": "your-secret-token",
"lease_id": "uuid-lease-id",
"fields": {
"scope": { "symbol": "UserService.authenticateWithOAuth" },
"reason": "Expanded to include new OAuth method",
"ttl_ms": 600000 // Extend to 10 minutes
}
}Release the scope when done:
// Tool: intent.end
{
"agent_id": "agent-alpha",
"session_id": "session-001",
"token": "your-secret-token",
"lease_id": "uuid-lease-id",
"status": "ended" // or "expired"
}Record what you changed:
// Tool: edits.append_summary
{
"agent_id": "agent-alpha",
"session_id": "session-001",
"token": "your-secret-token",
"file": "src/UserService.ts",
"summary": {
"outline": "Added OAuth 2.0 authentication flow",
"affected_symbols": ["UserService.authenticate", "OAuthProvider"],
"delta_hash": "sha256-abc123",
"tests_run": ["test/auth.test.ts"],
"result": "pass" // or "fail"
}
}Read the current state:
// Resource: resources.awareness.doc
{
"uri": "sasp://awareness/doc"
}
// Response:
{
"awareness_states": {
"12345": {
"agent_id": "agent-alpha",
"activity": "editing",
"file": "src/UserService.ts",
// ...
}
},
"intents": {
"lease-uuid": {
"lease_id": "lease-uuid",
"agent_id": "agent-alpha",
"file": "src/UserService.ts",
"status": "active",
// ...
}
},
"summaries_index": {
"src/UserService.ts": [
{
"agent_id": "agent-alpha",
"outline": "Added OAuth support",
// ...
}
]
}
}SASP includes three prompts to guide agents:
Guides agents to:
- Subscribe to awareness
- Read current snapshot
- Detect overlaps
- Declare intent or negotiate
# List prompts
curl -X POST http://localhost:3000/prompts/list
# Get prompt
curl -X POST http://localhost:3000/prompts/get -d '{"name": "plan-change"}'Guides agents through:
- Monitoring awareness while editing
- Updating awareness to "editing"
- Running tests
- Recording summary
- Ending intent
Strategies for resolving conflicts:
- Defer and wait
- Re-scope the change
- Coordinate via awareness
- Split the work
SASP enforces these overlap detection rules:
- Same symbol: Always conflicts
- Symbol vs Range: Symbol claims supersede range claims
- Range vs Range: Conflicts if ranges intersect (including adjacent lines)
- Different files: Never conflict
- Status: Only "active" intents block; "ended" and "expired" don't
// CONFLICT: Same symbol
Agent A: { symbol: "MyFunction" }
Agent B: { symbol: "MyFunction" } ❌
// CONFLICT: Symbol supersedes range
Agent A: { range: { startLine: 10, endLine: 20 } }
Agent B: { symbol: "MyFunction" } ❌ (if MyFunction is in that range)
// CONFLICT: Overlapping ranges
Agent A: { range: { startLine: 10, endLine: 20 } }
Agent B: { range: { startLine: 15, endLine: 25 } } ❌
// OK: Different symbols
Agent A: { symbol: "FunctionA" }
Agent B: { symbol: "FunctionB" } ✓
// OK: Non-overlapping ranges (requires at least one-line gap)
Agent A: { range: { startLine: 10, endLine: 20 } }
Agent B: { range: { startLine: 21, endLine: 30 } } ✓
// Note: Adjacent or touching ranges (e.g., endLine matching another intent's startLine) are considered overlapping.
// OK: Different files
Agent A: { file: "A.ts", symbol: "MyFunction" }
Agent B: { file: "B.ts", symbol: "MyFunction" } ✓Run the included demo to see two agents coordinating:
# Build first
npm run build
# Run demo
npm run demoThe demo shows:
- Agent A starts intent for
UserService.authenticate() - Agent B tries same symbol → rejected (overlap)
- Agent B waits via awareness
- Agent A completes and ends intent
- Agent B successfully starts intent
- Agent B completes edit
# Run all tests
npm test
# Run specific test suite
npm test unit_overlap
npm test unit_ttl
npm test integ_two_agents
# Watch mode
npm run test:watchTests cover:
- ✅ Overlap detection (symbol, range, precedence)
- ✅ TTL expiration and timer management
- ✅ Two-agent coordination flows
- ✅ Awareness propagation
- ✅ Intent updates and validation
sasp/
├── server/
│ └── src/
│ ├── index.ts # MCP server entrypoint
│ ├── config.ts # Configuration
│ ├── types.ts # TypeScript types
│ ├── core/
│ │ ├── auth.ts # Authentication
│ │ ├── overlap.ts # Overlap detection
│ │ └── ttl.ts # TTL management
│ ├── yjs/
│ │ └── doc.ts # Yjs document layer
│ ├── mcp/
│ │ └── tools/
│ │ ├── awareness.ts # Awareness tools
│ │ ├── intent.ts # Intent tools
│ │ └── edits.ts # Edit & git tools
│ ├── resources/
│ │ └── awareness_doc.ts # Snapshot resource
│ └── prompts/
│ ├── catalog.json
│ ├── plan-change.md
│ ├── apply-diff.md
│ └── negotiate-overlap.md
├── client-demo/
│ └── cli.ts # Demo client
├── tests/
│ ├── unit_overlap.test.ts
│ ├── unit_ttl.test.ts
│ └── integ_two_agents.test.ts
├── package.json
├── tsconfig.json
└── README.md
- Bearer Token: All tools require a valid authentication token
- Session Validation: agent_id and session_id must be registered
- Ownership: Agents can only update/end their own intents
- TTL Enforcement: Stale intents automatically expire
- Awareness Latency: ~50-200ms end-to-end for updates
- Intent Validation: Overlap checks are O(n) where n = active intents
- Yjs Sync: In-memory CRDT with optional WebSocket replication
This is v0.1.0 - a vibe-coded MVP built by AI agents, for AI agents. It's tongue-in-cheek, it's experimental, and it's probably got bugs. But it works, and it solves a real problem: coordinating multiple AI coding agents without turning your codebase into a dumpster fire.
For vibe coders everywhere: This is proof that you can ship something useful even when you're just vibing. No fancy planning, no enterprise architecture diagrams, just pure "let's solve this problem right now" energy. If you're building with AI agents and need them to stop stepping on each other's toes, give it a try.
git.commitis a stub (no actual git integration yet - we're saving that for 0.2)- No LSP integration for symbol indexing (you have to know your symbol names)
- No WebSocket provider enabled by default (single instance only)
- No persistent storage (state lost on restart - it's all vibes, no commitments)
- Real git integration with commit hooks
- LSP-based symbol resolution
- Multi-server sync via y-websocket
- Persistent storage with Yjs snapshots
- Per-branch room isolation
- Signed intents and audit logs
- GitHub integration (PR comments, checks)
Vibe coders welcome! This project was built in the spirit of "ship it and see what happens," so don't be shy:
- Fork the repository (or don't, just send vibes)
- Create a feature branch (or work directly on main if you're feeling spicy)
- Add tests for new functionality (we actually do believe in tests, surprisingly)
- Ensure all tests pass (
npm test) - Submit a pull request with good vibes only
House rules: Keep it real, keep it fun, and remember that merge conflicts are solved with communication, not combat.
MIT License - see LICENSE file for details
- Issues: https://github.com/yourusername/sasp/issues
- Documentation: https://github.com/yourusername/sasp/wiki