Skip to content

prvious/sage

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Sage

AI Agent Orchestrator for Laravel Applications

Sage is a local development dashboard that orchestrates AI coding agents across Git worktrees, providing instant preview URLs for each feature branch — like GitHub PR previews, but on your machine.

Currently Supported

  • Agent: Claude Code (requires claude CLI in system PATH and ANTHROPIC_API_KEY in environment)
  • Server: Laravel Artisan Serve (built-in development server with auto port assignment)
  • Platform: macOS, Linux, Windows (via WSL2)

Core Philosophy

  • Environment agnostic — Works on macOS, Linux, and Windows (via WSL)
  • Container optional — Run natively or in Docker, as long as project folders are accessible
  • Zero config server management — Sage uses Laravel's built-in artisan serve for instant preview URLs
  • Single binary distribution — Download and run. No PHP install required (FrankenPHP)

Key Features

Git Worktree Management

  • Create/delete worktrees from the dashboard
  • Each worktree gets an instant preview URL (e.g., feature-auth.myapp.local)
  • Visual status of all active worktrees

Server Driver System

  • Artisan Serve driver — Uses Laravel's built-in development server
  • Each worktree gets its own port automatically assigned
  • Zero configuration required - works out of the box

AI Agent Orchestration

  • Spawn Claude Code agent on specific worktrees
  • Real-time terminal output streaming
  • Model selection (claude-sonnet-4-20250514, claude-opus-4-20250514, etc.)
  • Agent switching (future: OpenCode, Cursor, Aider, etc.)

Dashboard Views

  • Kanban — Drag tasks through stages (idea → in-progress → review → done)
  • Terminal — Interact with main repo or any worktree
  • CLAUDE.md Editor — Manage agent instructions per project/worktree
  • Spec Generator — AI-assisted feature specification from ideas
  • Env Manager — View/edit .env files across worktrees

Tech Stack

Layer Tech Notes
Backend Laravel 12, Octane, Reverb
Frontend React 19, shadcn/ui, Tailwind v4, Inertia.js
Database SQLite (single file for data + queues)
Runtime FrankenPHP (static binary)
Process Laravel Queues (database driver), Symfony Process
Testing Pest + Pest Browser Full coverage: unit, feature, and E2E browser tests
Agents Claude Code Uses system ANTHROPIC_API_KEY from environment
Server Artisan Serve Built-in Laravel development server

Distribution

  1. Git clonegit clone https://github.com/Prvious/sage && cd sage && ./sage serve
  2. Binary download — Single executable for each platform, built with FrankenPHP static builds

Gotchas & Considerations

Must Address

Issue Solution
APP_URL per worktree Each worktree needs its own .env with correct APP_URL. Sage should auto-generate/patch this on worktree creation
Database isolation Worktrees sharing a DB will collide. Options: separate SQLite per worktree, or DB prefix, or user chooses
Port conflicts Artisan serve automatically assigns available ports per worktree to avoid conflicts
Windows path hell WSL2 file access from Windows is slow. Recommend keeping projects inside WSL filesystem
Reverb + Octane Both need to run. Sage binary needs to boot both (Reverb on separate port)
Pest Browser + FrankenPHP Need to verify Dusk/Pest Browser works when app runs via Octane. May need php artisan serve fallback for tests
Agent PATH Binary requires claude in system PATH. Sage reads ANTHROPIC_API_KEY from system environment, not config

Nice to Have

Feature Notes
Tunnel support Expose preview URLs publicly via Cloudflare Tunnel or ngrok for mobile testing
Webhook on merge Auto-cleanup worktree when branch is merged on GitHub
Cost tracking Track API token usage per task/agent
Diff viewer Show what agent changed before merge
Snapshot/restore Save worktree state before risky agent operations
Multi-project Manage multiple Laravel apps from one Sage instance

Security Considerations

  • Sage runs with access to your codebase + can execute commands. It should never be exposed publicly
  • Consider adding optional auth even for local (PIN code, etc.)
  • Agent API keys stored in Sage's .env — make sure it's gitignored

Proposed Data Model

Project
├── id, name, path, server_driver, base_url
│
├── Worktree (hasMany)
│   ├── id, branch_name, path, preview_url, status
│   └── env_overrides (JSON)
│
├── Task (hasMany)
│   ├── id, title, description, status, worktree_id
│   ├── prompt, agent_output, model, agent_type
│   └── commits (hasMany → Commit)
│
└── Spec (hasMany)
    ├── id, title, content (markdown)
    └── generated_from_idea

CLI Commands (Future)

sage serve                    # Start dashboard
sage worktree:create feature-x  # Create worktree + preview
sage worktree:list            # Show all worktrees
sage task:run "add dark mode" # Create task + spawn agent
sage preview:open feature-x   # Open preview URL in browser

Single binary build

Use FrankenPHP to build a single static binary of the application 'Sage'. The binary will start the webserver (FrankenPHP), start the queue (queue:work), and the scheduler (schedule:work). Worktrees use Laravel's artisan serve for individual preview servers.


Agent Abstraction via Manager class

use Illuminate\Support\Manager;
class Agent extends Manager
{
    public function createClaudeDriver(): ClaudeDriver
    {
        return $this->container->make(ClaudeDriver::class);
    }

    public function getDefaultDriver(){
        return config('sage.agents.default', default: 'claude');
    }
}

// Implementations
ClaudeDriver::class    // Uses system 'claude' binary and ANTHROPIC_API_KEY from environment
FakeAgentDriver::class // Fake agent for testing/mocks

Claude Code is CLI-based, so the abstraction is straightforward — spawn a process with system environment, stream output, track status. There must be a FakeAgentDriver::class for testing.

Important: The agent relies on the user's system environment:

  • claude binary must be in PATH
  • ANTHROPIC_API_KEY must be set in system environment (not in Sage's config)
  • All Process calls use ->env(getenv()) to access system environment

Config would look like:

// config/sage.php
'agents' => [
    'claude' => [
        'driver' => ClaudeDriver::class,
        'binary' => 'claude', // Resolved from system PATH
        'default_model' => 'claude-sonnet-4-20250514',
    ],
],

'default' => 'claude',

Testing Strategy

Pest (Unit + Feature)

// Unit: isolated logic
it('generates correct preview url from branch name', function () {
    expect(PreviewUrl::fromBranch('feature/auth-system'))
        ->toBe('feature-auth-system.myapp.local');
});

// Feature: full Laravel stack
it('creates a worktree with preview server', function () {
    $project = Project::factory()->create(['server_driver' => 'artisan']);

    post('/api/worktrees', [
        'branch' => 'feature-payments',
        'project_id' => $project->id,
    ])->assertCreated();

    $worktree = Worktree::where('branch_name', 'feature-payments')->first();

    expect($worktree)->not->toBeNull();
    expect($worktree->preview_url)->toContain('http://127.0.0.1:');
});

Pest Browser (E2E)

// Browser: real user flows
it('can create a task from the kanban board', function () {
    $this->browse(function (Browser $browser) {
        $browser->visit('/dashboard')
            ->click('@new-task-button')
            ->type('@task-prompt', 'Add user authentication with Laravel Breeze')
            ->select('@agent-select', 'claude')
            ->press('Create Task')
            ->waitForText('Task created')
            ->assertSee('Add user authentication');
    });
});

it('streams agent output in real-time', function () {
    $this->browse(function (Browser $browser) {
        $browser->visit('/tasks/1')
            ->waitFor('@terminal-output')
            ->waitForText('Creating files...', 30) // websocket streaming
            ->assertPresent('@agent-running-indicator');
    });
});

Test Isolation Challenges

Challenge Solution
Agent processes Mock Process facade or use a FakeAgentDriver
Reverb websockets Pest Browser can wait for DOM changes triggered by WS

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages