phantom-ai-coworker

安装量: 282
排名: #7226

安装

npx skills add https://github.com/aradotso/trending-skills --skill phantom-ai-coworker

Phantom AI Co-worker Skill by ara.so — Daily 2026 Skills collection. Phantom is an AI co-worker that runs on its own dedicated machine. Unlike chatbots, Phantom has persistent memory across sessions, creates and registers its own MCP tools at runtime, self-evolves based on observed patterns, communicates via Slack/email/Telegram/Webhook, and can build full infrastructure (databases, dashboards, APIs, pipelines) on its VM. Built on the Claude Agent SDK with TypeScript/Bun. Architecture Overview ┌─────────────────────────────────────────────────────┐ │ Phantom Agent │ │ ┌──────────┐ ┌──────────┐ ┌───────────────────┐ │ │ │ Claude │ │ Qdrant │ │ MCP Server │ │ │ │ Agent │ │ (memory) │ │ (dynamic tools) │ │ │ │ SDK │ │ │ │ │ │ │ └──────────┘ └──────────┘ └───────────────────┘ │ │ ┌──────────────────────────────────────────────┐ │ │ │ Channels │ │ │ │ Slack │ Email │ Telegram │ Webhook │ Discord │ │ │ └──────────────────────────────────────────────┘ │ │ ┌──────────────────────────────────────────────┐ │ │ │ Self-Evolution Engine │ │ │ │ observe → reflect → propose → validate → evolve│ │ └──────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────┘ Installation Docker (Recommended)

Download compose file and env template

curl -fsSL https://raw.githubusercontent.com/ghostwright/phantom/main/docker-compose.user.yaml -o docker-compose.yaml curl -fsSL https://raw.githubusercontent.com/ghostwright/phantom/main/.env.example -o .env

Edit .env with your credentials (see Configuration section)

nano .env

Start Phantom (includes Qdrant + Ollama)

docker compose up -d

Check health

curl http://localhost:3100/health

View logs

docker compose logs -f phantom From Source (Bun) git clone https://github.com/ghostwright/phantom.git cd phantom

Install dependencies

bun install

Copy env

cp .env.example .env

Edit .env

Start Qdrant (required for memory)

docker run -d -p 6333 :6333 qdrant/qdrant

Start Phantom

bun run start

Development mode with hot reload

bun run dev Configuration (.env)

=== Required ===

ANTHROPIC_API_KEY

Your Anthropic API key

=== Slack (required for Slack channel) ===

SLACK_BOT_TOKEN

xoxb-

Bot OAuth token

SLACK_APP_TOKEN

xapp-

App-level token (socket mode)

SLACK_SIGNING_SECRET

Signing secret

OWNER_SLACK_USER_ID

U0XXXXXXXXX

Your Slack user ID

=== Memory (Qdrant) ===

QDRANT_URL

http://localhost:6333

Qdrant vector DB URL

QDRANT_API_KEY

Optional, for cloud Qdrant

OLLAMA_URL

http://localhost:11434

Ollama for embeddings

=== Email (optional) ===

RESEND_API_KEY

For email sending via Resend

PHANTOM_EMAIL

phantom@yourdomain

Phantom's email address

=== Telegram (optional) ===

TELEGRAM_BOT_TOKEN

BotFather token

=== Infrastructure ===

PHANTOM_VM_DOMAIN

Public domain for served assets

PHANTOM_PORT

3100

HTTP port (default 3100)

=== Self-Evolution ===

EVOLUTION_VALIDATION_MODEL

claude-3-5-sonnet-20241022

Separate model for validation

EVOLUTION_ENABLED

true

=== Credentials Vault ===

CREDENTIAL_ENCRYPTION_KEY

AES-256-GCM key (auto-generated if empty)

Key Commands

Docker operations

docker compose up -d

Start all services

docker compose down

Stop all services

docker compose logs -f phantom

Stream logs

docker compose pull

Update to latest image

Bun development

bun run start

Production start

bun run dev

Dev mode with watch

bun run test

Run test suite

bun run build

Build TypeScript

Health checks

curl http://localhost:3100/health curl http://localhost:3100/status

MCP server endpoint

curl http://localhost:3100/mcp Core Concepts & Code Examples 1. Memory System (Qdrant + Embeddings) Phantom stores memories as vector embeddings for semantic recall across sessions. // src/memory/memory-manager.ts pattern import { QdrantClient } from '@qdrant/js-client-rest' ; const client = new QdrantClient ( { url : process . env . QDRANT_URL } ) ; // Storing a memory async function storeMemory ( content : string , metadata : Record < string , unknown

) { const embedding = await generateEmbedding ( content ) ; // via Ollama await client . upsert ( 'phantom_memory' , { points : [ { id : crypto . randomUUID ( ) , vector : embedding , payload : { content , timestamp : Date . now ( ) , ... metadata , } , } ] , } ) ; } // Recalling relevant memories async function recallMemories ( query : string , limit = 5 ) { const queryEmbedding = await generateEmbedding ( query ) ; const results = await client . search ( 'phantom_memory' , { vector : queryEmbedding , limit , with_payload : true , } ) ; return results . map ( r => r . payload ?. content ) ; } 2. Dynamic MCP Tool Registration Phantom creates MCP tools at runtime that persist across restarts. // Pattern: registering a dynamically created tool interface PhantomTool { name : string ; description : string ; inputSchema : Record < string , unknown

; handler : string ; // serialized or endpoint URL } // Phantom internally registers tools like this async function registerDynamicTool ( tool : PhantomTool ) { // Store tool definition in persistent storage await storeMemory ( JSON . stringify ( tool ) , { type : 'mcp_tool' , toolName : tool . name , } ) ; // Register with MCP server at runtime mcpServer . tool ( tool . name , tool . description , tool . inputSchema , async ( args ) => { return await executeToolHandler ( tool . handler , args ) ; } ) ; } // MCP server setup (how Phantom exposes tools to Claude Code) import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' ; const mcpServer = new McpServer ( { name : 'phantom' , version : '0.18.1' , } ) ; // Connect Claude Code to Phantom's MCP server: // In claude_desktop_config.json or .cursor/mcp.json: // { // "mcpServers": { // "phantom": { // "url": "http://your-phantom-vm:3100/mcp" // } // } // } 3. Slack Channel Integration // How Phantom handles Slack messages import { App } from '@slack/bolt' ; const slack = new App ( { token : process . env . SLACK_BOT_TOKEN , appToken : process . env . SLACK_APP_TOKEN , socketMode : true , signingSecret : process . env . SLACK_SIGNING_SECRET , } ) ; // Phantom listens for direct messages and mentions slack . event ( 'message' , async ( { event , say } ) => { if ( event . subtype ) return ; // Skip bot messages, edits const userMessage = ( event as any ) . text ; const userId = ( event as any ) . user ; // Recall relevant context from memory const memories = await recallMemories ( userMessage ) ; // Run Claude agent with memory context const response = await runPhantomAgent ( { message : userMessage , userId , memories , channel : ( event as any ) . channel , } ) ; await say ( { text : response , thread_ts : ( event as any ) . ts } ) ; } ) ; // Phantom DMs you when ready async function notifyOwnerReady ( ) { await slack . client . chat . postMessage ( { channel : process . env . OWNER_SLACK_USER_ID ! , text : "👻 Phantom is online and ready." , } ) ; } 4. Claude Agent SDK Integration // Core agent loop using Anthropic Agent SDK import Anthropic from '@anthropic-ai/sdk' ; const anthropic = new Anthropic ( { apiKey : process . env . ANTHROPIC_API_KEY , } ) ; async function runPhantomAgent ( { message , userId , memories , channel , } : PhantomAgentInput ) { const systemPrompt = buildSystemPrompt ( memories ) ; // Agentic loop with tool use const response = await anthropic . messages . create ( { model : 'claude-opus-4-5' , max_tokens : 8096 , system : systemPrompt , messages : [ { role : 'user' , content : message } ] , tools : await getAvailableTools ( ) , // includes dynamic MCP tools } ) ; // Handle tool calls in loop if ( response . stop_reason === 'tool_use' ) { return await handleToolCalls ( response , message , userId ) ; } // Store this interaction as memory await storeMemory ( User ${ userId } asked: ${ message } . I responded: ${ response . content } , { type : 'interaction' , userId , channel , } ) ; return extractTextContent ( response . content ) ; } function buildSystemPrompt ( memories : string [ ] ) : string { return You are Phantom, an AI co-worker with your own computer. You have persistent memory and can build infrastructure. Relevant memories from past sessions: ${ memories . map ( ( m , i ) => ${ i + 1 } . ${ m } ) . join ( '\n' ) } You have access to your VM, can install software, build tools, serve web pages on ${ process . env . PHANTOM_VM_DOMAIN } , and register new capabilities for yourself. ; } 5. Secure Credential Collection Phantom collects credentials via encrypted forms, never plain text. // Credential vault pattern import { createCipheriv , createDecipheriv , randomBytes } from 'crypto' ; const ALGORITHM = 'aes-256-gcm' ; const KEY = Buffer . from ( process . env . CREDENTIAL_ENCRYPTION_KEY ! , 'hex' ) ; function encryptCredential ( plaintext : string ) : string { const iv = randomBytes ( 16 ) ; const cipher = createCipheriv ( ALGORITHM , KEY , iv ) ; const encrypted = Buffer . concat ( [ cipher . update ( plaintext , 'utf8' ) , cipher . final ( ) , ] ) ; const authTag = cipher . getAuthTag ( ) ; return ${ iv . toString ( 'hex' ) } : ${ authTag . toString ( 'hex' ) } : ${ encrypted . toString ( 'hex' ) } ; } function decryptCredential ( ciphertext : string ) : string { const [ ivHex , authTagHex , encryptedHex ] = ciphertext . split ( ':' ) ; const iv = Buffer . from ( ivHex , 'hex' ) ; const authTag = Buffer . from ( authTagHex , 'hex' ) ; const encrypted = Buffer . from ( encryptedHex , 'hex' ) ; const decipher = createDecipheriv ( ALGORITHM , KEY , iv ) ; decipher . setAuthTag ( authTag ) ; return decipher . update ( encrypted ) + decipher . final ( 'utf8' ) ; } // Phantom generates a one-time secure form URL for credential collection async function generateCredentialForm ( service : string , fields : string [ ] ) { const token = randomBytes ( 32 ) . toString ( 'hex' ) ; // Store token with expiry await storeCredentialRequest ( token , { service , fields , expires : Date . now ( ) + 3600000 } ) ; return ${ process . env . PHANTOM_VM_DOMAIN } /credentials/ ${ token } ; } 6. Self-Evolution Engine Phantom observes its own behavior, proposes improvements, validates with a separate model, and evolves. // Evolution cycle pattern interface EvolutionProposal { observation : string ; currentBehavior : string ; proposedChange : string ; rationale : string ; version : string ; } async function runEvolutionCycle ( ) { if ( process . env . EVOLUTION_ENABLED !== 'true' ) return ; // 1. Observe recent interactions const recentMemories = await recallMemories ( 'recent interactions' , 50 ) ; // 2. Generate proposals with primary model const proposals = await generateEvolutionProposals ( recentMemories ) ; for ( const proposal of proposals ) { // 3. Validate with DIFFERENT model to avoid self-enhancement bias const isValid = await validateProposal ( proposal ) ; if ( isValid ) { // 4. Apply evolution and version it await applyEvolution ( proposal ) ; await versionEvolution ( proposal ) ; // Notify owner of evolution await notifySlack ( 🧬 I've evolved: ${ proposal . observation } \n→ ${ proposal . proposedChange } ) ; } } } async function validateProposal ( proposal : EvolutionProposal ) : Promise < boolean

{ // Uses a separate model instance to validate const validationResponse = await anthropic . messages . create ( { model : process . env . EVOLUTION_VALIDATION_MODEL ! , max_tokens : 1024 , messages : [ { role : 'user' , content : Evaluate this AI self-improvement proposal for safety and benefit: ${ JSON . stringify ( proposal , null , 2 ) } Respond with JSON: { "approved": boolean, "reason": string } , } ] , } ) ; // Parse and return approval const result = JSON . parse ( extractTextContent ( validationResponse . content ) ) ; return result . approved ; } 7. Infrastructure Building (VM Operations) // Phantom can run shell commands and Docker on its VM import { exec } from 'child_process' ; import { promisify } from 'util' ; const execAsync = promisify ( exec ) ; // Example: Phantom spinning up a Postgres container async function provisionDatabase ( projectName : string ) { const port = await findAvailablePort ( 5432 ) ; const password = randomBytes ( 16 ) . toString ( 'hex' ) ; const { stdout } = await execAsync ( docker run -d \ --name phantom-pg- ${ projectName } \ -e POSTGRES_PASSWORD= ${ password } \ -e POSTGRES_DB= ${ projectName } \ -p ${ port } :5432 \ postgres:16-alpine ) ; const connectionString = postgresql://postgres: ${ password } @localhost: ${ port } / ${ projectName } ; // Store connection string securely await storeCredential ( ${ projectName } _postgres , encryptCredential ( connectionString ) ) ; // Register as MCP tool for future use await registerDynamicTool ( { name : query_ ${ projectName } _db , description : Query the ${ projectName } PostgreSQL database , inputSchema : { sql : { type : 'string' } } , handler : postgres: ${ connectionString } , } ) ; return { connectionString , port } ; } // Serving a web page on Phantom's domain async function serveWebPage ( slug : string , htmlContent : string ) { const filePath = /var/phantom/public/ ${ slug } /index.html ; await Bun . write ( filePath , htmlContent ) ; return ${ process . env . PHANTOM_VM_DOMAIN } / ${ slug } ; } 8. Webhook Channel // Send messages to Phantom via webhook const response = await fetch ( 'http://your-phantom:3100/webhook/message' , { method : 'POST' , headers : { 'Content-Type' : 'application/json' , 'Authorization' : Bearer ${ process . env . PHANTOM_WEBHOOK_SECRET } , } , body : JSON . stringify ( { message : 'Analyze our GitHub issues and create a priority matrix' , userId : 'automation-system' , context : { source : 'ci-pipeline' , repo : 'myorg/myrepo' } , } ) , } ) ; const { response : agentResponse , taskId } = await response . json ( ) ; Connecting Claude Code to Phantom's MCP Server Once Phantom is running, connect Claude Code to use all of Phantom's registered tools: // ~/.claude/claude_desktop_config.json or .cursor/mcp.json { "mcpServers" : { "phantom" : { "url" : "http://your-phantom-vm:3100/mcp" } } } Or via CLI:

Claude Code CLI

claude mcp add phantom --url http://your-phantom-vm:3100/mcp

Verify connection

claude mcp list Docker Compose Structure

docker-compose.yaml (production user config)

services : phantom : image : ghostwright/phantom : latest ports : - "3100:3100" environment : - ANTHROPIC_API_KEY=$ { ANTHROPIC_API_KEY } - SLACK_BOT_TOKEN=$ { SLACK_BOT_TOKEN } - SLACK_APP_TOKEN=$ { SLACK_APP_TOKEN } - SLACK_SIGNING_SECRET=$ { SLACK_SIGNING_SECRET } - OWNER_SLACK_USER_ID=$ { OWNER_SLACK_USER_ID } - QDRANT_URL=http : //qdrant : 6333 - OLLAMA_URL=http : //ollama : 11434 - PHANTOM_VM_DOMAIN=$ { PHANTOM_VM_DOMAIN } - RESEND_API_KEY=$ { RESEND_API_KEY } volumes : - phantom_data : /var/phantom - /var/run/docker.sock : /var/run/docker.sock

For Docker-in-Docker

depends_on : - qdrant - ollama restart : unless - stopped qdrant : image : qdrant/qdrant : latest volumes : - qdrant_data : /qdrant/storage restart : unless - stopped ollama : image : ollama/ollama : latest volumes : - ollama_data : /root/.ollama restart : unless - stopped volumes : phantom_data : qdrant_data : ollama_data : Slack App Setup Go to api.slack.com/apps → Create New App → From manifest Use this manifest: display_information : name : Phantom features : bot_user : display_name : Phantom always_online : true app_home : messages_tab_enabled : true oauth_config : scopes : bot : - channels : history - channels : read - chat : write - chat : write.customize - files : write - groups : history - im : history - im : read - im : write - mpim : history - users : read settings : event_subscriptions : bot_events : - message.channels - message.groups - message.im - message.mpim interactivity : is_enabled : true socket_mode_enabled : true Install to workspace → copy Bot Token ( xoxb- ) to SLACK_BOT_TOKEN Generate App-Level Token with connections:write → copy to SLACK_APP_TOKEN Copy Signing Secret → SLACK_SIGNING_SECRET Get your user ID: In Slack, click your profile → copy Member ID → OWNER_SLACK_USER_ID Common Patterns Asking Phantom to Build a Tool In Slack: @phantom Create an MCP tool that queries our internal metrics API at https://metrics.internal/api/v2. It should accept a metric_name and time_range parameter and return JSON. Phantom will build the tool, register it with its MCP server, and confirm it's available. Scheduling Recurring Tasks @phantom Every weekday at 9am, check our GitHub repo myorg/myrepo for open PRs older than 3 days and post a summary to #engineering Requesting a Dashboard @phantom Build a dashboard showing our deployment frequency over the last 30 days. Make it shareable with the team. Phantom builds it, serves it at https://your-phantom-domain/dashboards/deploy-freq , and sends you the link. Memory Queries @phantom What did I tell you about our database architecture last week? @phantom What tools have you built for me so far? @phantom Summarize everything you know about Project X Troubleshooting Phantom not starting

Check all services are healthy

docker compose ps

Qdrant must be ready before Phantom

docker compose logs qdrant curl http://localhost:6333/health

Ollama must pull embedding model

docker compose logs ollama Memory not persisting

Verify Qdrant collections exist

curl http://localhost:6333/collections

Check Phantom can reach Qdrant

docker compose exec phantom curl http://qdrant:6333/health Slack not receiving messages Verify SLACK_APP_TOKEN starts with xapp- (not xoxb- ) Socket mode must be enabled in Slack App settings Check bot is invited to channels: /invite @Phantom Verify OWNER_SLACK_USER_ID is correct (not display name, actual ID) MCP tools not appearing in Claude Code

Verify MCP server is running

curl http://localhost:3100/mcp

Check tool registration

curl http://localhost:3100/mcp/tools

Restart Claude Code after adding MCP config

Evolution not triggering

Check env var

echo $EVOLUTION_ENABLED

should be "true"

Verify validation model is set

echo $EVOLUTION_VALIDATION_MODEL

Check logs for evolution cycle

docker compose logs phantom | grep -i evolv Docker socket permission denied

Add phantom user to docker group, or run with:

sudo docker compose up -d

Or add to docker-compose.yaml:

user: root

API Reference Endpoint Method Description /health GET Health check /status GET Agent status + uptime /mcp GET/POST MCP server endpoint /mcp/tools GET List registered tools /webhook/message POST Send message to agent /credentials/:token GET/POST Secure credential form /public/:slug GET Served static assets Version History & Rollback

Phantom versions its own evolution

View evolution history in logs

docker compose logs phantom | grep -i "evolved"

Pin to specific version

Edit docker-compose.yaml:

image: ghostwright/phantom:0.18.1

Roll back

docker compose down

Change image tag in compose file

docker compose up -d

返回排行榜