How to Add a Custom Agent

Build a Docker container that speaks the filepath Agent Protocol (FAP) and integrate it into the platform.

What you'll build

A Docker container that:

  • • Receives tasks via environment variables
  • • Reads user messages from stdin (NDJSON)
  • • Emits events to stdout (NDJSON)
  • • Runs in an isolated Linux environment

Prerequisites

  • • Docker installed locally
  • • filepath account with API key configured
  • • Basic understanding of NDJSON (one JSON object per line)

Step 1: Create the Dockerfile

Create a new directory for your agent:

mkdir my-custom-agent
cd my-custom-agent

Create Dockerfile:

FROM node:20-alpine

WORKDIR /workspace

# Copy your agent code
COPY package.json .
COPY index.js .

RUN npm install

# The container starts here
CMD ["node", "index.js"]

Step 2: Write the Agent Code

Create index.js:

const readline = require('readline');

// Read environment variables from filepath
const task = process.env.FILEPATH_TASK || '';
const apiKey = process.env.FILEPATH_API_KEY || '';
const model = process.env.FILEPATH_MODEL || '';
const agentId = process.env.FILEPATH_AGENT_ID || '';

// Startup message
console.log(JSON.stringify({
  type: 'status',
  state: 'running'
}));

console.log(JSON.stringify({
  type: 'text',
  content: `Starting task: ${task}`
}));

// Read user messages from stdin
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  terminal: false
});

rl.on('line', async (line) => {
  try {
    const msg = JSON.parse(line);

    if (msg.type === 'message') {
      // Echo back for demo purposes
      console.log(JSON.stringify({
        type: 'text',
        content: `Received: ${msg.content}`
      }));

      // Simulate some work
      console.log(JSON.stringify({
        type: 'command',
        command: 'echo "Processing..."'
      }));

      // Mark as done
      console.log(JSON.stringify({
        type: 'done'
      }));
    }
  } catch (e) {
    console.log(JSON.stringify({
      type: 'text',
      content: 'Error parsing input'
    }));
  }
});

// Handle graceful shutdown
process.on('SIGTERM', () => {
  console.log(JSON.stringify({
    type: 'status',
    state: 'idle'
  }));
  process.exit(0);
});

Create package.json:

{"name": "my-custom-agent", "version": "1.0.0", "main": "index.js"}

Step 3: Test Locally

Build and test your container:

# Build
docker build -t my-custom-agent .

# Test locally
echo '{"type":"message","content":"hello"}' | docker run -i \
  -e FILEPATH_TASK="Test task" \
  -e FILEPATH_API_KEY="sk-test" \
  my-custom-agent

You should see NDJSON output.

Step 4: Push to Registry

Push your image to a container registry:

# Tag for registry
docker tag my-custom-agent:latest ghcr.io/YOURNAME/my-custom-agent:latest

# Push
docker push ghcr.io/YOURNAME/my-custom-agent:latest

Step 5: Register in filepath

Currently, custom agents are added via PR to the filepath repo. Submit a PR adding your agent to the catalog.

Event Reference

Your agent should emit these event types:

{"type":"text","content":"Hello from agent"} — Assistant message
{"type":"tool","name":"git","status":"success"} — Tool execution
{"type":"done"} — Task complete

Best Practices

  • Flush stdout after each JSON line
  • Handle SIGTERM gracefully — save state and exit
  • Validate input — don't crash on malformed JSON
  • Emit status — let users know when you're working vs idle
  • Use /workspace — that's where files live

Next Steps