sugarcraft/sugar-crush

Chat-shell TUI for AI coding assistants — port of charmbracelet/crush. Pluggable Backend interface (ship your own Anthropic / OpenAI / Ollama / shell-out adapter). Markdown rendering of replies via CandyShine, scrollback viewport via SugarBits, input area via SugarBits TextArea.

Maintainers

Package info

github.com/sugarcraft/sugar-crush

Documentation

Type:project

pkg:composer/sugarcraft/sugar-crush

Transparency log

Statistics

Installs: 0

Dependents: 1

Suggesters: 0

Stars: 1

Open Issues: 0

dev-master 2026-07-04 22:48 UTC

This package is auto-updated.

Last update: 2026-07-10 03:50:46 UTC


README

sugar-crush

SugarCrush

CI codecov Packagist Version License PHP

demo

A terminal AI coding agent — PHP port of charmbracelet/crush. It is a candy-core TEA program (a real Model/Program render loop with buffer-diffed output and Markdown-rendered replies) wrapped around a full agent engine: multiple LLM providers, model-driven tool calling gated by hooks, prompt-injecting skills, sub-agents, an MCP client/server, and SQLite session history.

┌─ SugarCrush ───────────────────────────────────────┐
│ user> add a test for the Width helper              │
│                                                    │
│ assistant                                          │
│ I'll read the helper first, then write the test.   │
│   ⚙ Read  src/Util/Width.php                       │
│   ⚙ Edit  tests/Util/WidthTest.php                 │
│ Done — added 4 cases covering the clamp edges.     │
└────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────┐
│ > run them█                                        │
└────────────────────────────────────────────────────┘
 Enter to send · Esc / ^C to quit

History: SugarCrush absorbed the former experimental candy-crush port. There is now a single SugarCraft\Crush library.

Run it

composer install
./bin/sugarcrush

With no configuration the binary runs the offline EchoProvider through the full engine, so it launches with zero network and zero keys. Point it at a real model with environment variables:

# OpenAI
export SUGARCRUSH_PROVIDER=openai
export OPENAI_API_KEY=sk-...
export SUGARCRUSH_MODEL=gpt-4o          # optional; provider default otherwise
./bin/sugarcrush

SUGARCRUSH_PROVIDER accepts openai, anthropic, claude-code, sglang, bedrock, vertex, or custom. Each reads its own credentials from the environment (e.g. ANTHROPIC_API_KEY, AWS ambient creds for Bedrock, GOOGLE_APPLICATION_CREDENTIALS for Vertex). When a real provider is active, the binary wires the built-in coding tools (Bash/Read/Edit/Glob/Grep/WebFetch) and the safety hooks automatically.

Dependency-free shell-out

To avoid PHP SDKs entirely, set SUGARCRUSH_BACKEND_CMD to a command that reads JSON history on stdin and writes the reply to stdout:

export SUGARCRUSH_BACKEND_CMD=~/bin/anthropic.sh
./bin/sugarcrush
#!/usr/bin/env bash
# ~/bin/anthropic.sh — keeps PHP network-dep-free, swap models by editing this file
payload=$(jq -nc --argjson h "$(cat)" '{model:"claude-opus-4-8", max_tokens:4096, messages:$h}')
curl -sN https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" -d "$payload" | jq -r '.content[0].text'

Providers

SugarCraft\Crush\Providers\ProviderInterface is the single LLM abstraction (capability introspection, batch + \Generator streaming, function calling, embeddings, per-model cost). Build one directly or from config via ProviderFactory (which resolves ${VAR} / ${VAR:-default} from the environment):

use SugarCraft\Crush\Providers\ProviderFactory;

$factory  = new ProviderFactory();
$provider = $factory->create(['type' => 'openai', 'apiKey' => '${OPENAI_API_KEY}', 'model' => 'gpt-4o']);
Provider Type key Notes
OpenAI openai openai-php/client; function calling, embeddings, cost table
Anthropic anthropic real Messages API (/v1/messages, x-api-key)
Claude Code CLI claude-code drives the claude binary headless; native cost; JSON schema
SGLang sglang OpenAI-compatible self-hosted endpoints (Guzzle)
AWS Bedrock bedrock Converse API via aws/aws-sdk-php; per-model pricing
GCP Vertex vertex Anthropic-on-Vertex via an injectable predictor seam
Custom custom any OpenAI-compatible HTTP endpoint
Echo EchoProvider: offline, echoes the last turn; default + tests

The agent loop

EngineBackend bridges the chat-shell Backend seam to the engine. Each user turn runs a bounded agentic loop: call the provider through the Runtime, execute any tool calls through the hook gate, feed the results back, and repeat until the model answers without calling tools — or a maxSteps ceiling is hit.

use SugarCraft\Crush\Backend\EngineBackend;
use SugarCraft\Crush\Hooks\{HookManager, HookRegistry};
use SugarCraft\Crush\Tools\BuiltIn\{Bash, Read, Edit, Glob, Grep, WebFetch};

$hooks = new HookManager(new HookRegistry());
$hooks->registerBuiltIns();                       // audit + confirm-rm + protect-files

$backend = (EngineBackend::new($provider, 'gpt-4o'))
    ->withTools([new Bash(), new Read(), new Edit(), new Glob(), new Grep(), new WebFetch()])
    ->withHooks($hooks);

(new Program(new Chat(backend: $backend)))->run();

Capabilities

  • ToolsTools\BuiltIn\*: Bash, Read, Edit, Glob, Grep, WebFetch. Implement Tools\Tool for your own.
  • HooksHooks\*: pre/post-tool-use guards (allow / deny / modify the input). Built-ins: AuditHook, ConfirmRemoveHook, ProtectFilesHook. YAML config and external ScriptHook supported.
  • SkillsSkills\*: frontmatter SKILL.md files inject prompt context, matched by keyword/path. Discovered from built-ins, ~/.sugar-crush/skills, and <project>/.sugar-crush/skills (project wins). Ships php-best-practices, security-audit, phpunit-master, composer-wizard.
  • AgentsAgents\*: 6 sub-agent presets (coder/reviewer/debugger/architect/tester/devops) with their own model, tools, skills, and a streaming lifecycle.
  • MCPMCP\*: multi-server client (stdio + HTTP, .mcp.json, ${VAR} interpolation) and stdio/HTTP servers to host your own tools.
  • SessionsSession\SessionStore: SQLite (WAL) persistence of sessions/messages/tool-calls with FK-enforced cascade and age-based pruning.
  • Tokens & exportUtil\TokenTracker (token + cost accumulation) and Util\Exporter (Markdown / JSON / text transcripts).
  • Messages — typed Messages\{System,User,Assistant,ToolResult}Message; UserMessage carries file/image attachments; AssistantMessage carries tool calls + reasoning.

Architecture

SugarCrush keeps the proven sugar-crush chassis (the Chat candy-core Model, buffer-diff Renderer, bin/sugarcrush) and runs the ported engine behind it:

bin/sugarcrush
  └─ Program → Chat (Model: input, scrollback, inFlight gate, buffer-diff view)
       └─ Backend  ── EchoBackend / CommandBackend (simple)
                   └─ EngineBackend (agent loop)
                        └─ Runtime → ProviderInterface  (+ Tools · Hooks · Skills via App)

The chassis speaks the root Message value object; the engine speaks the typed Messages\* hierarchy; EngineBackend converts at the seam.

Custom provider

use SugarCraft\Crush\Providers\{ProviderInterface, CompleteRequest, CompleteResponse, EmbeddingsRequest, EmbeddingsResponse};

final class MyProvider implements ProviderInterface
{
    public function name(): string { return 'mine'; }
    public function supportsStreaming(): bool { return false; }
    public function supportsFunctionCalling(): bool { return true; }
    public function supportsVision(): bool { return false; }
    public function supportsJsonSchema(): bool { return false; }
    public function contextWindow(): int { return 128_000; }
    public function costPer1kTokens(string $model, string $direction): float { return 0.0; }
    public function complete(CompleteRequest $r): CompleteResponse { /* ... */ }
    public function completeStream(CompleteRequest $r): \Generator { /* yield CompleteResponse chunks */ }
    public function embeddings(EmbeddingsRequest $r): EmbeddingsResponse { /* ... */ }
}

Tests

cd sugar-crush && composer install && vendor/bin/phpunit

1,239 tests / 2,924 assertions. Coverage spans every subsystem: typed messages + attachments, the 6 built-in tools, all 7 providers (unit-tested with mocked transports — no live calls), the hook framework, skills discovery, sub-agents, the MCP client/servers, the SQLite store, token tracking, export, the TUI components, the Runtime orchestration (streaming accumulation, tool-result correlation, MODIFY hooks), and the EngineBackend agentic loop (incl. the maxSteps guard).