feathers-curlew
v0.0.2
Published
AI-friendly CLI toolkit for driving FeathersJS v5 servers, in-process or remote.
Maintainers
Readme
An AI-friendly CLI toolkit for driving FeathersJS v5 servers — in-process or remote. JSON in, JSON out.
You configure feathers-curlew into your app with app.configure(curlew()). Each Feathers method becomes
a verb that takes the service path as an argument — curlew find users, curlew patch users 42 — plus
authenticate, watch and your own custom commands (like sql). Output is JSON with non-zero exit codes
on error, so an AI agent can drive your server reliably.
Install
pnpm add feathers-curlew
# optional, for remote mode:
pnpm add @feathersjs/rest-client @feathersjs/authentication-clientQuickstart
Configure the plugin in your app, then point curlew at an app factory:
// src/app.ts
app.configure(curlew())
// curlew.config.ts
export default defineCurlewConfig({ createApp: () => createApp() })npx curlew services
npx curlew find users --query '{"$limit":5}'
npx curlew create users --data '{"email":"[email protected]","password":"secret"}'
npx curlew authenticate --email [email protected] --password secret
npx curlew find api/v1/users # nested paths need nothing special
npx curlew call messages markRead -d '{"id":42}' # Feathers custom methodAdd --pretty for indented JSON. Errors go to stderr as JSON with exit code 1. Full walkthrough:
Getting Started.
Teach your AI agent
feathers-curlew is built to be driven by an AI agent. Generate instructions tailored to your app — real
services, methods, custom commands, and the safety model — and drop them into your agent config:
npx curlew instructions --out AGENTS.md # idempotent managed block
npx curlew instructions --format skill --out .claude/skills/curlew/SKILL.md # Claude Code SkillRe-run after your services change; the block is replaced in place, never duplicated. See the AI Agents guide.
Modes
- In-process (default): boots your app (
app.setup()) and calls services directly — full DB access, supports customsql-style commands. - Remote: talks to a running server over REST/Socket.IO via
@feathersjs/client.
npx curlew --remote --url http://localhost:3030 find usersLarge results & live events
npx curlew findAll users --ndjson | head -20 # one record per line, paged through
npx curlew watch orders --query '{"status":"paid"}' # stream events (in-process)Permissions & safety
Calls are internal (full access) by default. Scope them per call, or change the default with
permission: 'authenticated':
npx curlew patch users 42 --data '{"role":"admin"}' # internal (default)
npx curlew find users --as 7 # run as a user
npx curlew find users --token "$JWT" # run with a tokenBulk writes (patch/remove with the id null) hit every matching record, so preview them — and make
confirmation mandatory if an agent is driving:
npx curlew remove users null -q '{"expired":true}' --dry-run
# {"dryRun":true,"method":"remove","service":"users","wouldAffect":412,"sample":[…]}export default defineCurlewConfig({ confirmBulk: true }) // bulk writes now need --yesSee Permissions.
Custom commands
import { defineCurlewCommand, defineCurlewConfig } from 'feathers-curlew'
export default defineCurlewConfig({
createApp: () => createApp(),
commands: [
defineCurlewCommand({
name: 'sql',
requiresApp: true,
args: { query: { type: 'positional', required: true } },
async run({ app, args, output }) {
const knex = app!.get('postgresqlClient')
output((await knex.raw(args.query)).rows)
},
}),
],
})Programmatic use
import { runCurlew } from 'feathers-curlew'
import { app } from './src/app'
process.exit(await runCurlew(app, { argv: ['find', 'users'] }))Documentation
Full docs (built with VitePress) live in docs/. Run them locally with pnpm docs:dev.
License
MIT
