<!-- Generated by Ruler -->


<!-- Source: .ruler/openskills.md -->

<skills_system priority="1">

## Available Skills

<!-- PRPM_MANIFEST_START -->

<skills_system priority="1">
<usage>
When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.

How to use skills (loaded into main context):
- Use the <path> from the skill entry below
- Invoke: Bash("cat <path>")
- The skill content will load into your current context
- Example: Bash("cat .openskills/backend-architect/SKILL.md")

Usage notes:
- Skills share your context window
- Do not invoke a skill that is already loaded in your context
</usage>

<available_skills>

<skill>
<name>prpm-development</name>
<description>Use when developing PRPM (Prompt Package Manager) - comprehensive knowledge base covering architecture, format conversion, package types, collections, quality standards, testing, and deployment</description>
<path>.openskills/prpm-development/SKILL.md</path>
</skill>

<skill>
<name>osgrep-skill</name>
<description>Skill for using osgrep semantic code search - teaches how to effectively search codebases using natural language queries instead of exact string matching</description>
<path>.openskills/osgrep-skill/SKILL.md</path>
</skill>

</available_skills>
</skills_system>

<!-- PRPM_MANIFEST_END -->

</skills_system>



<!-- Source: .ruler/prpm-development.md -->

<!-- Package: prpm-development -->
<!-- Author: user -->
<!-- Description: Use when developing PRPM (Prompt Package Manager) - comprehensive knowledge base covering architecture, format conversion, package types, collections, quality standards, testing, and deployment -->

# Individual package

Use when developing PRPM (Prompt Package Manager) - comprehensive knowledge base covering architecture, format conversion, package types, collections, quality standards, testing, and deployment

## Mission

Build the npm/cargo/pip equivalent for AI development artifacts. Enable developers to discover, install, share, and manage prompts across Cursor, Claude Code, Continue, Windsurf, and future AI editors.

## Core Architecture

### Git Workflow - CRITICAL RULES

```bash
git checkout -b feature/your-feature-name
   # or
   git checkout -b fix/bug-description
```

## Package Types

- Knowledge and guidelines for AI assistants

- `.claude/skills/`, `.cursor/rules/`

- `@prpm/pulumi-troubleshooting`, `@typescript/best-practices`

- Autonomous AI agents for multi-step tasks

- `.claude/agents/`, `.cursor/agents/`

- `@prpm/code-reviewer`, `@cursor/debugging-agent`

- Specific instructions or constraints for AI behavior

- `.cursor/rules/`, `.cursorrules`

- `@cursor/react-conventions`, `@cursor/test-first`

- Extensions that add functionality

- `.cursor/plugins/`, `.claude/plugins/`

- Reusable prompt templates

- `.prompts/`, project-specific directories

- Multi-step automation workflows

- `.workflows/`, `.github/workflows/`

- Executable utilities and scripts

- `scripts/`, `tools/`, `.bin/`

- Reusable file and project templates

- `templates/`, project-specific directories

- Model Context Protocol servers

- `.mcp/servers/`

## Format Conversion System

- Cursor (.mdc)

- MDC frontmatter with `ruleType`, `alwaysApply`, `description`

- Markdown body

- Simple, focused on coding rules

- No structured tools/persona definitions

- Claude (agent format)

- YAML frontmatter: `name`, `description`

- Optional: `tools` (comma-separated), `model` (sonnet/opus/haiku/inherit)

- Markdown body

- Supports persona, examples, instructions

- Continue (JSON)

- JSON configuration

- Simple prompts, context rules

- Limited metadata support

- Windsurf

- Similar to Cursor

- Markdown-based

- Basic structure

- Missing tools: -10 points

- Missing persona: -5 points

- Missing examples: -5 points

- Unsupported sections: -10 points each

- Format-specific features lost: -5 points

- **Canonical ↔ Claude**: Nearly lossless (95-100%)

- **Canonical ↔ Cursor**: Lossy on tools/persona (70-85%)

- **Canonical ↔ Continue**: Most lossy (60-75%)

## Collections System

### Collection Structure

```json
{
  "id": "@collection/nextjs-pro",
  "name": "Next.js Professional Setup",
  "description": "Complete Next.js development setup",
  "category": "frontend",
  "packages": [
    {
      "packageId": "react-best-practices",
      "required": true,
      "reason": "Core React patterns"
    },
    {
      "packageId": "typescript-strict",
      "required": true,
      "reason": "Type safety"
    },
    {
      "packageId": "tailwind-helper",
      "required": false,
      "reason": "Styling utilities"
    }
  ]
}
```

### Installation Formats (Priority Order)

```bash
prpm install collections/nextjs-pro
prpm install collections/nextjs-pro@2.0.0
```

### Registry Resolution Logic

```typescript
// When scope is 'collection' (default from CLI for collections/* prefix):
if (scope === 'collection') {
  // Search across ALL scopes, prioritize by:
  // 1. Official collections (official = true)
  // 2. Verified authors (verified = true)
  // 3. Most downloads
  // 4. Most recent
  SELECT * FROM collections
  WHERE name_slug = $1
  ORDER BY official DESC, verified DESC, downloads DESC, created_at DESC
  LIMIT 1
} else {
  // Explicit scope: exact match only
  SELECT * FROM collections
  WHERE scope = $1 AND name_slug = $2
  ORDER BY created_at DESC
  LIMIT 1
}
```

### CLI Resolution Logic

```typescript
// Parse collection spec:
// - collections/nextjs-pro → scope='collection', name_slug='nextjs-pro'
// - khaliqgant/nextjs-pro → scope='khaliqgant', name_slug='nextjs-pro'
// - @khaliqgant/nextjs-pro → scope='khaliqgant', name_slug='nextjs-pro'
// - nextjs-pro → scope='collection', name_slug='nextjs-pro'

const matchWithScope = collectionSpec.match(/^@?([^/]+)\/([^/@]+)(?:@(.+))?$/);
if (matchWithScope) {
  [, scope, name_slug, version] = matchWithScope;
} else {
  // No scope: default to 'collection'
  [, name_slug, version] = collectionSpec.match(/^([^/@]+)(?:@(.+))?$/);
  scope = 'collection';
}
```

### Version Resolution

```bash
prpm install collections/nextjs-pro

prpm install collections/nextjs-pro@2.0.4

prpm install khaliqgant/nextjs-pro@2.0.4
```

### Error Handling

```bash
prpm install collections/nonexistent
```

## Quality & Ranking System

- (0-30 points):

- Total downloads (weighted by recency)

- Stars/favorites

- Trending velocity

- (0-30 points):

- User ratings (1-5 stars)

- Review sentiment

- Documentation completeness

- (0-20 points):

- Verified author badge

- Original creator vs fork

- Publisher reputation

- Security scan results

- (0-10 points):

- Last updated date (<30 days = 10 points)

- Release frequency

- Active maintenance

- (0-10 points):

- Has README

- Has examples

- Has tags

- Complete metadata

## Technical Stack

- **Commander.js**: CLI framework

- **Fastify Client**: HTTP client for registry

- **Tar**: Package tarball creation/extraction

- **Chalk**: Terminal colors

- **Ora**: Spinners for async operations

- **Fastify**: High-performance web framework

- **PostgreSQL**: Primary database with GIN indexes

- **Redis**: Caching layer for converted packages

- **GitHub OAuth**: Authentication provider

- **Docker**: Containerized deployment

- **Vitest**: Unit and integration tests

- **100% Coverage Goal**: Especially for format converters

- **Round-Trip Tests**: Ensure conversion quality

- **Fixtures**: Real-world package examples

## Testing Standards

### Key Testing Patterns

```typescript
// Format converter test
describe('toCursor', () => {
  it('preserves data in roundtrip', () => {
    const result = toCursor(canonical);
    const back = fromCursor(result.content);
    expect(back).toEqual(canonical);
  });
});

// CLI command test
describe('install', () => {
  it('downloads and installs package', async () => {
    await handleInstall('test-pkg', { as: 'cursor' });
    expect(fs.existsSync('.cursor/rules/test-pkg.md')).toBe(true);
  });
});
```

## Development Workflow

### Package Manager: npm (NOT pnpm)

```bash
npm install

npm install --workspace=@pr-pm/cli

npm test

npm run build

npm run dev --workspace=prpm
```

### Dependency Management Best Practices

```typescript
// BAD - tar-stream is imported dynamically at runtime
const tarStream = await import('tar-stream');
```

### Environment Variable Management

```bash
NEW_FEATURE_API_KEY=your-key-here
```

## Security Standards

- **No Secrets in DB**: Never store GitHub tokens, use session IDs

- **SQL Injection**: Parameterized queries only

- **Rate Limiting**: Prevent abuse of registry API

- **Content Security**: Validate package contents before publishing

## Performance Considerations

- **Batch Operations**: Use Promise.all for independent operations

- **Database Indexes**: GIN for full-text, B-tree for lookups

- **Caching Strategy**: Cache converted packages, not raw data

- **Lazy Loading**: Don't load full package data until needed

- **Connection Pooling**: Reuse PostgreSQL connections

## Deployment

### Webapp (S3 Static Export) ⚠️ CRITICAL

```typescript
// ❌ Dynamic route (doesn't work with 'use client')
     // /app/shared/[token]/page.tsx
     const params = useParams();
     const token = params.token;

     // ✅ Query string with Suspense (works with 'use client')
     // /app/shared/page.tsx
     import { Suspense } from 'react';

     function Content() {
       const searchParams = useSearchParams();
       const token = searchParams.get('token');
       // ... component logic
     }

     export default function Page() {
       return (
         <Suspense fallback={<div>Loading...</div>}>
           <Content />
         </Suspense>
       );
     }
```

### Publishing PRPM to NPM

```bash
npm version patch --workspace=prpm --workspace=@prpm/registry-client

npm version minor --workspace=prpm
```

## Common Patterns

### CLI Command Structure

```typescript
export async function handleCommand(args: Args, options: Options) {
  const startTime = Date.now();
  try {
    const config = await loadUserConfig();
    const client = getRegistryClient(config);
    const result = await client.fetchData();
    console.log('✅ Success');
    await telemetry.track({ command: 'name', success: true });
  } catch (error) {
    console.error('❌ Failed:', error.message);
    await telemetry.track({ command: 'name', success: false });
    process.exit(1);
  }
}
```

### Registry Route Structure

```typescript
server.get('/:id', {
  schema: { /* OpenAPI schema */ },
}, async (request, reply) => {
  const { id } = request.params;
  if (!id) return reply.code(400).send({ error: 'Missing ID' });
  const result = await server.pg.query('SELECT...');
  return result.rows[0];
});
```

### Format Converter Structure

```typescript
export function toFormat(pkg: CanonicalPackage): ConversionResult {
  const warnings: string[] = [];
  let qualityScore = 100;
  const content = convertSections(pkg.content.sections, warnings);
  const lossyConversion = warnings.some(w => w.includes('not supported'));
  if (lossyConversion) qualityScore -= 10;
  return { content, format: 'target', warnings, qualityScore, lossyConversion };
}
```

## Naming Conventions

- **Files**: kebab-case (`registry-client.ts`, `to-cursor.ts`)

- **Types**: PascalCase (`CanonicalPackage`, `ConversionResult`)

- **Functions**: camelCase (`getPackage`, `convertToFormat`)

- **Constants**: UPPER_SNAKE_CASE (`DEFAULT_REGISTRY_URL`)

- **Database**: snake_case (`package_id`, `created_at`)

- **API Requests/Responses**: snake_case (`package_id`, `session_id`, `created_at`)

- **Important**: All API request and response fields use snake_case to match PostgreSQL database conventions

- Internal service methods may use camelCase, but must convert to snake_case at API boundaries

- TypeScript interfaces for API types should use snake_case fields

- Examples: `PlaygroundRunRequest.package_id`, `CreditBalance.reset_at`

## Documentation Standards

- **Inline Comments**: Explain WHY, not WHAT

- **JSDoc**: Required for public APIs

- **README**: Keep examples up-to-date

- **Markdown Docs**: Use code blocks with language tags

- **Changelog**: Follow Keep a Changelog format

- **Continuous Accuracy**: Documentation must be continuously updated and tended to for accuracy

- When adding features, update relevant docs immediately

- When fixing bugs, check if docs need corrections

- When refactoring, verify examples still work

- Review docs quarterly for outdated information

- Keep CLI docs, README, and Mintlify docs in sync

## Overview

Complete knowledge base for developing PRPM - the universal package manager for AI prompts, agents, and rules.

## Reference Documentation

- `format-conversion.md` - Complete format conversion specs

- `package-types.md` - All package types with examples

- `collections.md` - Collections system and examples

- `quality-ranking.md` - Quality and ranking algorithms

- `testing-guide.md` - Testing patterns and standards

- `deployment.md` - Deployment procedures



<!-- Source: .ruler/thoroughness.md -->

<!-- Package: thoroughness -->
<!-- Author: user -->
<!-- Description: Use when implementing complex multi-step tasks, fixing critical bugs, or when quality and completeness matter more than speed - ensures comprehensive implementation without shortcuts through systematic analysis, implementation, and verification phases -->

# Thoroughness

Use when implementing complex multi-step tasks, fixing critical bugs, or when quality and completeness matter more than speed - ensures comprehensive implementation without shortcuts through systematic analysis, implementation, and verification phases

## Purpose

This skill ensures comprehensive, complete implementation of complex tasks without shortcuts. Use this when quality and completeness matter more than speed.

## When to Use

- Fixing critical bugs or compilation errors

- Implementing complex multi-step features

- Debugging test failures

- Refactoring large codebases

- Production deployments

- Any task where shortcuts could cause future problems

## Methodology

- **Identify All Issues**

- List every error, warning, and failing test

- Group related issues together

- Prioritize by dependency order

- Create issue hierarchy (what blocks what)

- **Root Cause Analysis**

- Don't fix symptoms, find root causes

- Trace errors to their source

- Identify patterns in failures

- Document assumptions that were wrong

- **Create Detailed Plan**

- Break down into atomic steps

- Estimate time for each step

- Identify dependencies between steps

- Plan verification for each step

- Schedule breaks/checkpoints

- **Fix Issues in Dependency Order**

- Start with foundational issues

- Fix one thing completely before moving on

- Test after each fix

- Document what was changed and why

- **Verify Each Fix**

- Write/run tests for the specific fix

- Check for side effects

- Verify related functionality still works

- Document test results

- **Track Progress**

- Mark issues as completed

- Update plan with new discoveries

- Adjust time estimates

- Note any blockers immediately

- **Run All Tests**

- Unit tests

- Integration tests

- E2E tests

- Manual verification

- **Cross-Check Everything**

- Review all changed files

- Verify compilation succeeds

- Check for console errors/warnings

- Test edge cases

- **Documentation**

- Update relevant docs

- Add inline comments for complex fixes

- Document known limitations

- Create issues for future work

## Anti-Patterns to Avoid

- ❌ Fixing multiple unrelated issues at once

- ❌ Moving on before verifying a fix works

- ❌ Assuming similar errors have the same cause

- ❌ Skipping test writing "to save time"

- ❌ Copy-pasting solutions without understanding

- ❌ Ignoring warnings "because it compiles"

- ❌ Making changes without reading existing code first

## Quality Checkpoints

- [ ] Can I explain why this fix works?

- [ ] Have I tested this specific change?

- [ ] Are there any side effects?

- [ ] Is this the root cause or a symptom?

- [ ] Will this prevent similar issues in the future?

- [ ] Is the code readable and maintainable?

- [ ] Have I documented non-obvious decisions?

## Example Workflow

### Bad Approach (Shortcut-Driven)

*Bad example*

```
1. See 24 TypeScript errors
2. Add @ts-ignore to all of them
3. Hope tests pass
4. Move on
```

### Good Approach (Thoroughness-Driven)

*Good example*

```
1. List all 24 errors systematically
2. Group by error type (7 missing types, 10 unknown casts, 7 property access)
3. Find root causes:
   - Missing @types/tar package
   - No type assertions on fetch responses
   - Implicit any types in callbacks
4. Fix by category:
   - Install @types/tar (fixes 7 errors)
   - Add proper type assertions to registry-client.ts (fixes 10 errors)
   - Add explicit parameter types (fixes 7 errors)
5. Test after each category
6. Run full test suite
7. Document what was learned
```

## Time Investment

- Initial: 2-3x slower than shortcuts

- Long-term: 10x faster (no debugging later, no rework)

- Quality: Near-perfect first time

- Maintenance: Minimal

## Success Metrics

- ✅ 100% of tests passing

- ✅ Zero warnings in production build

- ✅ All code has test coverage

- ✅ Documentation is complete and accurate

- ✅ No known issues or TODOs left behind

- ✅ Future developers can understand the code

## Mantras

- "Slow is smooth, smooth is fast"

- "Do it right the first time"

- "Test everything, assume nothing"

- "Document for your future self"

- "Root causes, not symptoms"



<!-- Source: .ruler/typescript-type-safety.md -->

<!-- Package: typescript-type-safety -->
<!-- Author: user -->
<!-- Description: Use when encountering TypeScript any types, type errors, or lax type checking - eliminates type holes and enforces strict type safety through proper interfaces, type guards, and module augmentation -->

# TypeScript Type Safety

Use when encountering TypeScript any types, type errors, or lax type checking - eliminates type holes and enforces strict type safety through proper interfaces, type guards, and module augmentation

## Overview

**Zero tolerance for `any` types.** Every `any` is a runtime bug waiting to happen.

Replace `any` with proper types using interfaces, `unknown` with type guards, or generic constraints. Use `@ts-expect-error` with explanation only when absolutely necessary.

## When to Use

- Use when you see:

- `: any` in function parameters or return types

- `as any` type assertions

- TypeScript errors you're tempted to ignore

- External libraries without proper types

- Catch blocks with implicit `any`

- Don't use for:

- Already properly typed code

- Third-party `.d.ts` files (contribute upstream instead)

## Type Safety Hierarchy

**Prefer in this order:**
1. Explicit interface/type definition
2. Generic type parameters with constraints
3. Union types
4. `unknown` (with type guards)
5. `never` (for impossible states)

**Never use:** `any`

## Quick Reference

| Pattern | Bad | Good |
|---------|-----|------|
| **Error handling** | `catch (error: any)` | `catch (error) { if (error instanceof Error) ... }` |
| **Unknown data** | `JSON.parse(str) as any` | `const data = JSON.parse(str); if (isValid(data)) ...` |
| **Type assertions** | `(request as any).user` | `(request as AuthRequest).user` |
| **Double casting** | `return data as unknown as Type` | Align interfaces instead: make types compatible |
| **External libs** | `const server = fastify() as any` | `declare module 'fastify' { ... }` |
| **Generics** | `function process(data: any)` | `function process<T extends Record<string, unknown>>(data: T)` |

## Implementation

### Error Handling

```typescript
// ❌ BAD
try {
  await operation();
} catch (error: any) {
  console.error(error.message);
}

// ✅ GOOD - Use unknown and type guard
try {
  await operation();
} catch (error) {
  if (error instanceof Error) {
    console.error(error.message);
  } else {
    console.error('Unknown error:', String(error));
  }
}

// ✅ BETTER - Helper function
function toError(error: unknown): Error {
  if (error instanceof Error) return error;
  return new Error(String(error));
}

try {
  await operation();
} catch (error) {
  const err = toError(error);
  console.error(err.message);
}
```

### Unknown Data Validation

```typescript
// ❌ BAD
const data = await response.json() as any;
console.log(data.user.name);

// ✅ GOOD - Type guard
interface UserResponse {
  user: {
    name: string;
    email: string;
  };
}

function isUserResponse(data: unknown): data is UserResponse {
  return (
    typeof data === 'object' &&
    data !== null &&
    'user' in data &&
    typeof data.user === 'object' &&
    data.user !== null &&
    'name' in data.user &&
    typeof data.user.name === 'string'
  );
}

const data = await response.json();
if (isUserResponse(data)) {
  console.log(data.user.name); // Type-safe
}
```

### Module Augmentation

```typescript
// ❌ BAD
const user = (request as any).user;
const db = (server as any).pg;

// ✅ GOOD - Augment third-party types
import { FastifyRequest, FastifyInstance } from 'fastify';

interface AuthUser {
  user_id: string;
  username: string;
  email: string;
}

declare module 'fastify' {
  interface FastifyRequest {
    user?: AuthUser;
  }

  interface FastifyInstance {
    pg: PostgresPlugin;
  }
}

// Now type-safe everywhere
const user = request.user; // AuthUser | undefined
const db = server.pg;      // PostgresPlugin
```

### Generic Constraints

```typescript
// ❌ BAD
function merge(a: any, b: any): any {
  return { ...a, ...b };
}

// ✅ GOOD - Constrained generic
function merge<
  T extends Record<string, unknown>,
  U extends Record<string, unknown>
>(a: T, b: U): T & U {
  return { ...a, ...b };
}
```

### Type Alignment (Avoid Double Casts)

```typescript
// ❌ BAD - Double cast indicates misaligned types
interface SearchPackage {
  id: string;
  type: string;  // Too loose
}

interface RegistryPackage {
  id: string;
  type: PackageType;  // Specific enum
}

return data.packages as unknown as RegistryPackage[];  // Hiding incompatibility

// ✅ GOOD - Align types from the source
interface SearchPackage {
  id: string;
  type: PackageType;  // Use same specific type
}

interface RegistryPackage {
  id: string;
  type: PackageType;  // Now compatible
}

return data.packages;  // No cast needed - types match
```

## Common Mistakes

| Mistake | Why It Fails | Fix |
|---------|--------------|-----|
| Using `any` for third-party libs | Loses all type safety | Use module augmentation or `@types/*` package |
| `as any` for complex types | Hides real type errors | Create proper interface or use `unknown` |
| `as unknown as Type` double casts | Misaligned interfaces | Align types at source - same enums/unions |
| Skipping catch block types | Unsafe error access | Use `unknown` with type guards or toError helper |
| Generic functions without constraints | Allows invalid operations | Add `extends` constraint |
| Ignoring `ts-ignore` accumulation | Tech debt compounds | Fix root cause, use `@ts-expect-error` with comment |

## TSConfig Strict Settings

### Enable all strict options for maximum type safety:

```json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true
  }
}
```

## Type Audit Workflow

1. **Find**: `grep -r ": any\|as any" --include="*.ts" src/`
2. **Categorize**: Group by pattern (errors, requests, external libs)
3. **Define**: Create interfaces/types for each category
4. **Replace**: Systematic replacement with proper types
5. **Validate**: `npm run build` must succeed
6. **Test**: All tests must pass

## Real-World Impact

- Before type safety:

- Runtime errors from undefined properties

- Silent failures from type mismatches

- Hours debugging production issues

- Difficult refactoring

- After type safety:

- Errors caught at compile time

- IntelliSense shows all available properties

- Confident refactoring with compiler help

- Self-documenting code

- Type safety isn't about making TypeScript happy - it's about preventing runtime bugs. Every `any` you eliminate is a production bug you prevent.

<!-- prpm:snippet:start @agent-relay/agent-relay-snippet@1.1.4 -->
# 🚨 CRITICAL: Relay-First Communication Rule

**When you receive a relay message from another agent (marked `Relay message from [name]`), you MUST respond ONLY via relay protocol. NEVER respond with direct text output.**

## The Rule

- **Receiving a relay message?** → Must use `->relay-file:msg` ALWAYS
- **Non-relay questions?** → Text responses are OK
- **Agent-to-agent communication?** → ALWAYS use relay protocol

## Examples of Relay Messages (require relay response)

```
Relay message from khaliqgant [mknra7wr]: Did you see this?
Relay message from Worker1 [abc123]: Task complete
Relay message from alice [xyz789] [#general]: Question for the team
```

---

# Agent Relay

Real-time agent-to-agent messaging via file-based protocol.

## Sending Messages

**TWO STEPS REQUIRED:**

**Step 1:** EXECUTE this bash command (you MUST run it via your Bash/shell tool, not just display it):

```bash
cat > $AGENT_RELAY_OUTBOX/msg << 'EOF'
TO: AgentName

Your message here.
EOF
```

**Step 2:** Output the trigger `->relay-file:msg` directly in your response text (after the bash command succeeds).

⚠️ **CRITICAL**: You must EXECUTE the bash command above - do NOT just display it as a code block. The file must actually be created on disk. Then output the trigger as plain text.

✅ CORRECT: Run Bash tool → then output `->relay-file:msg`
❌ WRONG: Display the bash code without executing it

> **Note**: `$AGENT_RELAY_OUTBOX` is automatically set by agent-relay when spawning agents. Data is stored in `.agent-relay/` within your project directory.

## Synchronous Messaging

By default, messages are fire-and-forget. Add `[await]` to block until the recipient ACKs:

```
->relay:AgentB [await] Please confirm
```

Custom timeout (seconds or minutes):

```
->relay:AgentB [await:30s] Please confirm
->relay:AgentB [await:5m] Please confirm
```

Recipients auto-ACK after processing when a correlation ID is present.

## Message Format

```
TO: Target
THREAD: optional-thread

Message body (everything after blank line)
```

| TO Value | Behavior |
|----------|----------|
| `AgentName` | Direct message |
| `*` | Broadcast to all |
| `#channel` | Channel message |

## Agent Naming (Local vs Bridge)

**Local communication** uses plain agent names. The `project:` prefix is **ONLY** for cross-project bridge mode.

| Context | Correct | Incorrect |
|---------|---------|-----------|
| Local (same project) | `TO: Lead` | `TO: project:lead` |
| Local (same project) | `TO: Worker1` | `TO: myproject:Worker1` |
| Bridge (cross-project) | `TO: frontend:Designer` | N/A |
| Bridge (to another lead) | `TO: otherproject:lead` | N/A |

**Common mistake**: Using `project:lead` when communicating locally. This will fail because the relay looks for an agent literally named "project:lead".

```bash
# CORRECT - local communication to Lead agent
cat > $AGENT_RELAY_OUTBOX/msg << 'EOF'
TO: Lead

Status update here.
EOF
```

```bash
# WRONG - project: prefix is only for bridge mode
cat > $AGENT_RELAY_OUTBOX/msg << 'EOF'
TO: project:lead

This will fail locally!
EOF
```

## Spawning & Releasing

**IMPORTANT**: The filename is always `spawn` (not `spawn-agentname`) and the trigger is always `->relay-file:spawn`. Spawn agents one at a time sequentially.

### CLI Options

The `CLI` header specifies which AI CLI to use. Valid values:

| CLI Value | Description |
|-----------|-------------|
| `claude` | Claude Code (Anthropic) |
| `codex` | Codex CLI (OpenAI) |
| `gemini` | Gemini CLI (Google) |
| `aider` | Aider coding assistant |
| `goose` | Goose AI assistant |

**Step 1:** EXECUTE this bash command (run it, don't just display it):
```bash
# Spawn a Claude agent
cat > $AGENT_RELAY_OUTBOX/spawn << 'EOF'
KIND: spawn
NAME: WorkerName
CLI: claude

Task description here.
EOF
```
**Step 2:** Output: `->relay-file:spawn`

```bash
# Spawn a Codex agent
cat > $AGENT_RELAY_OUTBOX/spawn << 'EOF'
KIND: spawn
NAME: CodexWorker
CLI: codex

Task description here.
EOF
```

**Step 1:** EXECUTE this bash command (run it, don't just display it):
```bash
# Release
cat > $AGENT_RELAY_OUTBOX/release << 'EOF'
KIND: release
NAME: WorkerName
EOF
```
**Step 2:** Output: `->relay-file:release`

## When You Are Spawned

If you were spawned by another agent:

1. **Check who spawned you**: `echo $AGENT_RELAY_SPAWNER`
2. **Your first message** is your task from your spawner - reply to THEM, not "spawner"
3. **Report status** to your spawner (your lead), not broadcast

```bash
# Check your spawner
echo "I was spawned by: $AGENT_RELAY_SPAWNER"
```

**Step 1:** EXECUTE this bash command:
```bash
# Reply to your spawner
cat > $AGENT_RELAY_OUTBOX/msg << 'EOF'
TO: $AGENT_RELAY_SPAWNER

ACK: Starting on the task.
EOF
```
**Step 2:** Output: `->relay-file:msg`

## Receiving Messages

Messages appear as:
```
Relay message from Alice [abc123]: Content here
```

Channel messages include `[#channel]`:
```
Relay message from Alice [abc123] [#general]: Hello!
```
Reply to the channel shown, not the sender.

## Protocol

- **ACK** when you receive a task: `ACK: Brief description`
- **DONE** when complete: `DONE: What was accomplished`
- Send status to your **lead** (the agent in `$AGENT_RELAY_SPAWNER`), not broadcast

## Headers Reference

| Header | Required | Description |
|--------|----------|-------------|
| TO | Yes (messages) | Target agent/channel |
| KIND | No | `message` (default), `spawn`, `release` |
| NAME | Yes (spawn/release) | Agent name |
| CLI | Yes (spawn) | CLI to use: `claude`, `codex`, `gemini`, `aider`, `goose` |
| THREAD | No | Thread identifier |
<!-- prpm:snippet:end @agent-relay/agent-relay-snippet@1.1.4 -->
