@grainulation/farmer
v1.1.5
Published
Mobile-first permission dashboard for AI coding agents
Downloads
226
Maintainers
Readme
Farmer sits between your AI coding agent and your terminal, giving you a visual dashboard to approve, deny, or respond to tool calls in real time. Desktop and mobile.
Install
npm install -g @grainulation/farmerQuick start
# 1. Install hooks (once)
farmer connect --global # all projects, or:
farmer connect # current project only
# 2. Start the dashboard
farmer start
# 3. Open the token URL printed to the terminal
# 4. Start claude in any project -- hooks route automaticallyFeatures
- Desktop + mobile dashboard -- session sidebar, permission cards with syntax-highlighted code, activity feed, mobile swipe card view
- Agent-agnostic hook protocol -- Claude Code adapter ships first; write your own for other agents
- Multi-session -- manage multiple AI sessions from one dashboard
- Multi-user roles -- admin and viewer tokens with separate permissions; viewers see read-only cards with "Waiting for admin" labels, admin controls hidden
- Trust tiers -- paranoid (approve everything, overrides session-level rules), standard (auto-approve reads), autonomous (auto-approve most)
- AskUserQuestion -- deny-to-respond pattern lets you answer agent questions from the dashboard
- Security -- three-token auth (admin + viewer + hook), HMAC-signed invite links with expiry, CSRF protection, CSP headers, opportunistic Bearer auth on
/hooks/*(see below), audit logging - Data persistence -- activity and messages survive server restarts
- Stale server guard -- auto-approves when no dashboard is connected (prevents CLI blocking)
CLI
farmer start [--port 9090] [--token <secret>] [--viewer-token <secret>] [--trust-proxy] [--data-dir <path>]
farmer stop
farmer statusTokens are persisted in a JSON token file (.farmer-token in the data directory). The file stores three tokens:
admin-- full dashboard accessviewer-- read-only dashboard accesshook-- narrow-scope token for/hooks/*Bearer auth; never grants dashboard access
The file is generated automatically on first startup (mode 0600) and is backwards compatible with the legacy plain-text format. When upgrading from a pre-bs-19 farmer, a fresh hook token is generated and appended on first boot.
Hook protocol
Farmer exposes the following hook endpoints. All accept POST with JSON body, localhost only:
| Endpoint | Purpose |
| ---------------------- | ------------------------------------------------------------- |
| /hooks/permission | Tool permission requests (blocking -- waits for approve/deny) |
| /hooks/activity | Tool completion events (non-blocking) |
| /hooks/notification | Messages, questions, agent events (non-blocking) |
| /hooks/lifecycle | Session start/end events |
| /hooks/stop | Graceful shutdown signal |
| /hooks/sprint-status | Sprint state push from grainulator notifier |
| /hooks/harvest | Harvest analytics events |
Hook authentication (opportunistic Bearer)
On a shared host (Citrix / multi-user Linux), anything on 127.0.0.1 is reachable by other local users. Without auth, any local process could forge sprint-status POSTs and pollute another user's dashboard. Farmer uses an opportunistic Bearer auth scheme to fix this without breaking pre-upgrade users:
- If
.farmer-tokencontains ahookfield at server start, every/hooks/*POST MUST includeAuthorization: Bearer <hookToken>. Missing or wrong token =>401 {"error":"unauthorized"}. - If the
hookfield is absent (pre-bs-19 file format), farmer logs a one-time stderr warning (hook auth disabled — create .farmer-token to enable ...) and accepts loopback POSTs for backward compat. - The admin/viewer tokens are intentionally NOT accepted here; a leaked admin token cannot be used to spam
/hooks/*, and a leaked hook token cannot log into the dashboard.
Local hook scripts (e.g. grainulator's sprint-status-notifier.cjs) read the hook token from the farmer data dir (FARMER_DATA_DIR env var or ~/.farmer) and attach the Bearer header automatically. Override with the FARMER_TOKEN env var for tests or CI.
Writing an adapter
To support a new AI agent, extend BaseAdapter in lib/adapters/base.js:
import { BaseAdapter } from "@grainulation/farmer/lib/adapters/base.js";
class MyAgentAdapter extends BaseAdapter {
get name() {
return "My Agent";
}
parseRequest(body) {
/* ... */
}
formatResponse(decision, context) {
/* ... */
}
getToolName(body) {
/* ... */
}
isQuestion(body) {
/* ... */
}
parseNotification(body) {
/* ... */
}
}Architecture
bin/farmer.js CLI entry point (start/stop/status)
lib/server.js Core HTTP + SSE server
lib/adapters/ Agent adapter interface + Claude Code adapter
lib/persistence.js State persistence (atomic write, debounced)
lib/connect.js One-step hook installation and settings.json management
lib/security.js Token auth, CSRF, CSP, PID lock, audit log
public/index.html Dashboard (inline JS, no build step)Zero third-party dependencies
Farmer has zero third-party runtime dependencies — depends only on @grainulation/barn (internal ecosystem utilities). SSE for real-time streaming, polling as fallback. Everything else is Node built-ins.
Part of the grainulation ecosystem
| Tool | Role | | ------------------------------------------------------------ | ----------------------------------------------------------- | | wheat | Research engine -- grow structured evidence | | farmer | Permission dashboard -- approve AI actions in real time | | barn | Shared tools -- templates, validators, sprint detection | | mill | Format conversion -- export to PDF, CSV, slides, 26 formats | | silo | Knowledge storage -- reusable claim libraries and packs | | harvest | Analytics -- cross-sprint patterns and prediction scoring | | orchard | Orchestration -- multi-sprint coordination and dependencies | | grainulation | Unified CLI -- single entry point to the ecosystem |
Releases
See CHANGELOG.md for release history.
License
MIT
