@robinson_ai_systems/free-agent-core
v1.0.15
Published
Portable, repo-agnostic Free Agent core with spec-first codegen and quality gates
Readme
Free Agent Core
Portable, repo-agnostic Free Agent with spec-first codegen and quality gates.
Features
- Portable: Runs anywhere, not tied to any repository
- CLI:
--repo,--task,--kindarguments for any repository - Auto-discovery: Works without per-repo configuration
- Per-repo adapters: Optional
.free-agent/config.jsonfor custom commands - Spec-first codegen: Registry path/URL, not repo-bound
- Quality gates: Build/lint/test loop with refinement
- Patch guard: Validates diffs before applying
- Handlers generated: To temp dir or
.free-agent/.generated
Installation
pnpm add @robinson_ai_systems/free-agent-coreUsage
CLI
# Run against any repository
pnpm free-agent --repo /path/to/repo --task "Implement feature X" --kind feature
# With spec registry
export FREE_AGENT_SPEC=https://your-host/tools.registry.json
pnpm free-agent --repo /path/to/repo --task "Fix bug Y" --kind bugfixProgrammatic
import { runFreeAgent } from "@robinson_ai_systems/free-agent-core";
await runFreeAgent({
repo: "/path/to/repo",
task: "Implement feature X",
kind: "feature",
});Per-Repo Configuration
Create .free-agent/config.json in your repository:
{
"name": "my-repo",
"cmd": {
"install": "pnpm i",
"eslint": "pnpm lint",
"tsc": "pnpm tsc --noEmit",
"tests": "pnpm vitest run"
},
"specRegistry": "https://your-host/tools.registry.json",
"codegenOutDir": ".free-agent/.generated"
}If no config exists, Free Agent auto-discovers:
- Package manager:
pnpmornpm - Linter:
npx eslint . --max-warnings=0 - Type checker:
npx tsc --noEmit - Tests:
npx vitest run
Spec Registry
Set the spec registry via environment variable or adapter config:
# File path
export FREE_AGENT_SPEC=/abs/path/tools.registry.json
# HTTP URL
export FREE_AGENT_SPEC=https://your-host/tools.registry.jsonHandlers are generated from the registry into a temp directory or .free-agent/.generated.
Architecture
Adapter Interface
type Adapter = {
name: string;
cmd: Cmds;
specRegistry?: string;
codegenOutDir?: string;
prepare(repo: string): Promise<void>;
run(repo: string, cmd: string): Promise<{ code: number; out: string }>;
synthesize(args: { repo: string; task: string; kind: string }): Promise<{ diff: string }>;
refine(args: { repo: string; task: string; diagnostics: any; lastDiff: string }): Promise<{ diff: string }>;
applyPatch(repo: string, unifiedDiff: string): Promise<void>;
};Pipeline
- Prepare: Install dependencies, bootstrap
- Synthesize: Generate initial code via LLM
- Apply: Apply patch with validation
- Quality Gates: Run eslint, tsc, tests
- Refine: If gates fail, refine and retry (max 3 attempts)
Spec-First Codegen
Handlers are generated from a registry:
import { generateFromRegistry } from "@robinson_ai_systems/free-agent-core/spec";
const code = generateFromRegistry({
services: {
api: {
baseEnv: "API_URL",
defaultBase: "https://api.example.com",
endpoints: {
get_user: {
path: "/users/{id}",
method: "GET",
pathParams: ["id"],
},
},
},
},
});Patch Guard
Validates diffs before applying:
import { validatePatchUnifiedDiff } from "@robinson_ai_systems/free-agent-core";
validatePatchUnifiedDiff(diff); // Throws if invalidRejects:
- Placeholders: "Placeholder for real implementation"
anytypes in added lines- Fake paths: "path/to/gateway/handlers.ts"
- Hardcoded collections: "default_collection"
- TODO/FIXME comments
Environment Variables
FREE_AGENT_SPEC: Path or URL to spec registryFREE_AGENT_GENERATED_HANDLERS: Path to generated handlers (set by codegen)
License
MIT
