- Updated E6-z3ed-cli-design.md to reflect the current state and design goals of the z3ed CLI, emphasizing its evolution into a powerful tool for ROM hacking with AI integration. - Introduced E6-z3ed-reference.md as a comprehensive technical reference, detailing command usage, implementation guides, and troubleshooting tips. - Expanded README.md to provide a clearer overview of z3ed, including documentation structure and quick start guides for users. - Enhanced the archive README.md to clarify the purpose of archived documents and their relevance to the project's history and technical decisions.
25 KiB
z3ed CLI Technical Reference
Version: 0.1.0-alpha
Last Updated: October 2, 2025
Status: Production Ready (macOS), Windows Testing Pending
Table of Contents
- Architecture Overview
- Command Reference
- Implementation Guide
- Testing & Validation
- Development Workflows
- Troubleshooting
- API Reference
- Platform Notes
Architecture Overview
System Components
┌─────────────────────────────────────────────────────────┐
│ AI Agent Layer (LLM) │
│ └─ Natural language prompts │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ z3ed CLI (Command-Line Interface) │
│ ├─ agent run --prompt "..." --sandbox │
│ ├─ agent test --prompt "..." (IT-02) │
│ ├─ agent list │
│ ├─ agent diff --proposal-id <id> │
│ ├─ agent describe [--resource <name>] │
│ ├─ rom info/validate/diff/generate-golden │
│ ├─ palette export/import/list │
│ ├─ overworld get-tile/set-tile │
│ └─ dungeon list-rooms/add-object │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ Service Layer (Singleton Services) │
│ ├─ ProposalRegistry (proposal tracking) │
│ ├─ RomSandboxManager (isolated ROM copies) │
│ ├─ ResourceCatalog (machine-readable API specs) │
│ ├─ GuiAutomationClient (gRPC wrapper) │
│ ├─ TestWorkflowGenerator (NL → test steps) │
│ └─ PolicyEvaluator (YAML constraints) [Planned] │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ ImGuiTestHarness (gRPC Server) │
│ ├─ Ping (health check) │
│ ├─ Click (button, menu, tab) │
│ ├─ Type (text input) │
│ ├─ Wait (condition polling) │
│ ├─ Assert (state validation) │
│ └─ Screenshot (capture) [Stub] │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ YAZE GUI (ImGui Application) │
│ ├─ ProposalDrawer (Debug → Agent Proposals) │
│ │ ├─ List/detail views │
│ │ ├─ Accept/Reject/Delete │
│ │ └─ ROM merging │
│ └─ Editor Windows │
│ ├─ Overworld Editor │
│ ├─ Dungeon Editor │
│ ├─ Palette Editor │
│ └─ Graphics Editor │
└─────────────────────────────────────────────────────────┘
Data Flow: Proposal Lifecycle
User: z3ed agent run "Make soldiers red" --sandbox
│
▼
┌────────────────────────┐
│ MockAIService │ → ["palette export sprites_aux1 4 soldier.col"]
└────────┬───────────────┘
│
▼
┌────────────────────────┐
│ RomSandboxManager │ → Creates: /tmp/.../sandboxes/20251002T100000/zelda3.sfc
└────────┬───────────────┘
│
▼
┌────────────────────────┐
│ Execute Commands │ → Runs: palette export on sandbox ROM
└────────┬───────────────┘
│
▼
┌────────────────────────┐
│ ProposalRegistry │ → Creates: proposal-20251002T100000/
│ │ • execution.log
│ │ • diff.txt (if generated)
└────────┬───────────────┘
│
▼ (User opens YAZE GUI)
┌────────────────────────┐
│ ProposalDrawer │ → Displays: List of proposals
└────────┬───────────────┘
│
▼ (User clicks "Accept")
┌────────────────────────┐
│ AcceptProposal() │ → 1. Load sandbox ROM
│ │ 2. rom_->WriteVector(0, sandbox_rom.vector())
│ │ 3. ROM marked dirty
│ │ 4. User saves ROM
└────────────────────────┘
Command Reference
Agent Commands
agent run - Execute AI-driven ROM modifications
z3ed agent run --prompt "<description>" --rom <file> [--sandbox]
Options:
--prompt <text> Natural language description of desired changes
--rom <file> Path to ROM file (default: current ROM)
--sandbox Create isolated copy for testing (recommended)
Example:
z3ed agent run --prompt "Change soldier armor to red" \
--rom=zelda3.sfc --sandbox
Output:
- Proposal ID
- Sandbox path
- Command execution log
- Next steps guidance
agent list - Show all proposals
z3ed agent list
Example Output:
=== Agent Proposals ===
ID: proposal-20251002T100000-1
Status: Pending
Created: 2025-10-02 10:00:00
Prompt: Change soldier armor to red
Commands: 3
Bytes Changed: 128
Total: 1 proposal(s)
agent diff - Show proposal changes
z3ed agent diff [--proposal-id <id>]
Options:
--proposal-id <id> View specific proposal (default: latest pending)
Example:
z3ed agent diff --proposal-id proposal-20251002T100000-1
Output:
- Proposal metadata
- Execution log
- Diff content
- Next steps
agent describe - Export machine-readable API specs
z3ed agent describe [--format <yaml|json>] [--resource <name>] [--output <file>]
Options:
--format <type> Output format: yaml or json (default: yaml)
--resource <name> Filter to specific resource (rom, palette, etc.)
--output <file> Write to file instead of stdout
Examples:
z3ed agent describe --format yaml
z3ed agent describe --format json --resource rom
z3ed agent describe --output docs/api/z3ed-resources.yaml
Resources Available:
rom- ROM file operationspatch- Patch applicationpalette- Palette manipulationoverworld- Overworld editingdungeon- Dungeon editingagent- Agent commands
agent test - Automated GUI testing (IT-02)
z3ed agent test --prompt "<test_description>" [--host <hostname>] [--port <port>]
Options:
--prompt <text> Natural language test description
--host <hostname> Test harness hostname (default: localhost)
--port <port> Test harness port (default: 50052)
--timeout <seconds> Maximum test duration (default: 30)
Supported Prompt Patterns:
- "Open <Editor> editor"
- "Open <Editor> and verify it loads"
- "Click <Button>"
- "Type '<text>' in <input>"
Examples:
z3ed agent test --prompt "Open Overworld editor"
z3ed agent test --prompt "Open Dungeon editor and verify it loads"
z3ed agent test --prompt "Click Save button"
z3ed agent test --prompt "Type 'zelda3.sfc' in filename input"
Prerequisites:
- YAZE running with test harness:
./yaze --enable_test_harness --test_harness_port=50052 --rom_file=zelda3.sfc & - z3ed built with gRPC support:
cmake -B build-grpc-test -DYAZE_WITH_GRPC=ON cmake --build build-grpc-test --target z3ed
ROM Commands
rom info - Display ROM metadata
z3ed rom info --rom <file>
Example:
z3ed rom info --rom=zelda3.sfc
rom validate - Verify ROM integrity
z3ed rom validate --rom <file>
Example:
z3ed rom validate --rom=zelda3.sfc
rom diff - Compare two ROMs
z3ed rom diff --rom1 <file1> --rom2 <file2>
Example:
z3ed rom diff --rom1=zelda3.sfc --rom2=zelda3_modified.sfc
rom generate-golden - Create reference checksums
z3ed rom generate-golden --rom <file> --output <json_file>
Example:
z3ed rom generate-golden --rom=zelda3.sfc --output=golden.json
Palette Commands
palette export - Export palette to file
z3ed palette export <group_name> <palette_id> <output_file>
Example:
z3ed palette export sprites_aux1 4 soldier.col
palette import - Import palette from file
z3ed palette import <group_name> <palette_id> <input_file>
Example:
z3ed palette import sprites_aux1 4 soldier_red.col
palette list - Show available palettes
z3ed palette list [--group <name>]
Example:
z3ed palette list --group sprites_aux1
Overworld Commands
overworld get-tile - Get tile at coordinates
z3ed overworld get-tile --map <id> --x <x> --y <y>
Example:
z3ed overworld get-tile --map=0 --x=100 --y=50
overworld set-tile - Set tile at coordinates
z3ed overworld set-tile --map <id> --x <x> --y <y> --tile-id <id>
Example:
z3ed overworld set-tile --map=0 --x=100 --y=50 --tile-id=0x1234
Dungeon Commands
dungeon list-rooms - List all dungeon rooms
z3ed dungeon list-rooms --dungeon <id>
Example:
z3ed dungeon list-rooms --dungeon=0
dungeon add-object - Add object to room
z3ed dungeon add-object --dungeon <id> --room <id> --object <type>
Example:
z3ed dungeon add-object --dungeon=0 --room=5 --object=chest
Implementation Guide
Building with gRPC Support
macOS (Recommended)
# Install dependencies (via vcpkg or system)
# vcpkg is handled automatically by CMake
# Configure with gRPC enabled
cmake -B build-grpc-test -DYAZE_WITH_GRPC=ON
# Build YAZE and z3ed
cmake --build build-grpc-test --target yaze -j$(sysctl -n hw.ncpu)
cmake --build build-grpc-test --target z3ed -j$(sysctl -n hw.ncpu)
# First build takes 15-20 minutes (gRPC compilation)
# Incremental builds: 5-10 seconds
Windows (Experimental)
# Install vcpkg (one-time setup)
git clone https://github.com/Microsoft/vcpkg.git C:\vcpkg
C:\vcpkg\bootstrap-vcpkg.bat
C:\vcpkg\vcpkg integrate install
# Install dependencies
C:\vcpkg\vcpkg install grpc:x64-windows abseil:x64-windows sdl2:x64-windows
# Configure and build
cmake -B build -DCMAKE_TOOLCHAIN_FILE=C:\vcpkg\scripts\buildsystems\vcpkg.cmake `
-DYAZE_WITH_GRPC=ON -A x64
cmake --build build --config Release --target yaze
cmake --build build --config Release --target z3ed
Windows Notes:
- Test harness not yet validated on Windows
- Use static linking to avoid DLL conflicts
- See
docs/02-build-instructions.mdfor details
Starting Test Harness
Basic Usage
# Start YAZE with test harness enabled
./build-grpc-test/bin/yaze.app/Contents/MacOS/yaze \
--enable_test_harness \
--test_harness_port=50052 \
--rom_file=assets/zelda3.sfc &
# Verify server is running
lsof -i :50052
# Should show yaze process listening
Configuration Options
--enable_test_harness Enable gRPC test harness (default: false)
--test_harness_port=<port> Port number (default: 50051)
--rom_file=<file> ROM to load on startup (optional)
Testing RPCs with grpcurl
# Install grpcurl
brew install grpcurl
# Health check
grpcurl -plaintext -import-path src/app/core/proto \
-proto imgui_test_harness.proto \
-d '{"message":"test"}' 127.0.0.1:50052 yaze.test.ImGuiTestHarness/Ping
# Click button
grpcurl -plaintext -import-path src/app/core/proto \
-proto imgui_test_harness.proto \
-d '{"target":"button:Overworld","type":"LEFT"}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Click
# Type text
grpcurl -plaintext -import-path src/app/core/proto \
-proto imgui_test_harness.proto \
-d '{"target":"input:Search","text":"tile16","clear_first":true}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Type
# Wait for condition
grpcurl -plaintext -import-path src/app/core/proto \
-proto imgui_test_harness.proto \
-d '{"condition":"window_visible:Overworld Editor","timeout_ms":5000}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Wait
# Assert state
grpcurl -plaintext -import-path src/app/core/proto \
-proto imgui_test_harness.proto \
-d '{"condition":"visible:Main Window"}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/Assert
Testing & Validation
Automated E2E Test Script
# Run comprehensive test suite
./scripts/test_harness_e2e.sh
# Expected: All 6 tests pass
# - Ping (health check)
# - Click (button interaction)
# - Type (text input)
# - Wait (condition polling)
# - Assert (state validation)
# - Screenshot (stub - returns not implemented)
Manual Testing Workflow
1. Create Proposal
./build/bin/z3ed agent run \
--rom=assets/zelda3.sfc \
--prompt "Test proposal" \
--sandbox
2. List Proposals
./build/bin/z3ed agent list
3. View Diff
./build/bin/z3ed agent diff
4. Review in GUI
# Start YAZE
./build/bin/yaze.app/Contents/MacOS/yaze
# Navigate: Debug → Agent Proposals
# Select proposal → Review → Accept/Reject/Delete
Performance Benchmarks
| Operation | Typical Time | Notes |
|---|---|---|
| Ping RPC | < 10ms | Health check overhead |
| Click RPC | 50-200ms | Widget lookup + event |
| Type RPC | 100-300ms | Focus + clear + input |
| Wait RPC | 100-5000ms | Depends on condition |
| Assert RPC | 10-100ms | State query |
| Full Workflow | 1-2s | Click + Wait + Assert |
| Proposal Creation | < 1s | Mock AI service |
| ROM Merge | < 100ms | Memory copy |
Development Workflows
Adding New Agent Commands
- Create Handler (
src/cli/handlers/<resource>.cc)
absl::Status HandleNewCommand(const CommandOptions& options) {
// Implementation
return absl::OkStatus();
}
- Register Command (
src/cli/modern_cli.cc)
if (absl::GetFlag(FLAGS_new_resource) == "new-action") {
return HandleNewCommand(options);
}
- Add to Resource Catalog (
src/cli/service/resource_catalog.cc)
catalog.resources.push_back({
.name = "new_resource",
.description = "Description",
.actions = {{
.name = "new-action",
.description = "Action description",
.arguments = {/* ... */},
.effects = {/* ... */},
.returns = {/* ... */}
}}
});
- Update Documentation
- Add to
docs/api/z3ed-resources.yaml(regenerate viaagent describe) - Add examples to relevant guides
Adding New Test Harness RPCs
- Update Proto (
src/app/core/proto/imgui_test_harness.proto)
service ImGuiTestHarness {
rpc NewOperation(NewRequest) returns (NewResponse);
}
message NewRequest {
string parameter = 1;
}
message NewResponse {
bool success = 1;
string message = 2;
}
- Implement Handler (
src/app/core/imgui_test_harness_service.cc)
grpc::Status ImGuiTestHarnessServiceImpl::NewOperation(
grpc::ServerContext* context,
const NewRequest* request,
NewResponse* response) {
// Implementation
response->set_success(true);
response->set_message("Operation completed");
return grpc::Status::OK;
}
- Rebuild
cmake --build build-grpc-test --target yaze
- Test
grpcurl -plaintext -import-path src/app/core/proto \
-proto imgui_test_harness.proto \
-d '{"parameter":"value"}' \
127.0.0.1:50052 yaze.test.ImGuiTestHarness/NewOperation
Adding Test Workflow Patterns
- Add Pattern Matcher (
src/cli/service/test_workflow_generator.cc)
bool MatchesNewPattern(const std::string& prompt, YourParams* params) {
std::regex pattern(R"(your regex pattern)");
std::smatch matches;
if (std::regex_search(prompt, matches, pattern)) {
// Extract parameters
return true;
}
return false;
}
- Add Workflow Builder
TestWorkflow BuildNewPatternWorkflow(const YourParams& params) {
TestWorkflow workflow;
workflow.description = "Your workflow description";
// Add steps
workflow.steps.push_back({
.type = TestStep::kClick,
.target = "button:Name",
/* ... */
});
return workflow;
}
- Integrate into Generator
absl::StatusOr<TestWorkflow> TestWorkflowGenerator::GenerateFromPrompt(
const std::string& prompt) {
YourParams params;
if (MatchesNewPattern(prompt, ¶ms)) {
return BuildNewPatternWorkflow(params);
}
// ... other patterns
}
Troubleshooting
Common Issues
Port Already in Use
Problem: Failed to start gRPC server: Address already in use
Solutions:
# Find and kill existing instance
lsof -i :50052
kill <PID>
# Or use different port
./yaze --enable_test_harness --test_harness_port=50053
Connection Refused
Problem: Error connecting to server: Connection refused
Solutions:
- Verify server is running:
lsof -i :50052 - Check firewall settings
- Ensure correct port number
Widget Not Found
Problem: Button 'XYZ' not found
Solutions:
- Verify widget label is correct (case-sensitive)
- Check if widget is in active window
- Wait for window to be visible first
- Use Assert to check widget exists
Build Errors - Boolean Flag
Problem: std::stringstream >> bool doesn't parse "true"/"false"
Solution: Already fixed in src/util/flag.h with template specialization
Build Errors - Incomplete Type
Problem: error: delete called on 'grpc::Server' that is incomplete
Solution: Ensure destructor implementation is in .cc file, not header
Debug Mode
Enable verbose logging:
# In z3ed
export YAZE_LOG_LEVEL=debug
./z3ed agent test --prompt "..."
# In test harness
./yaze --enable_test_harness --log_level=debug
Test Harness Diagnostics
# Check server status
grpcurl -plaintext 127.0.0.1:50052 list
# Check available services
grpcurl -plaintext 127.0.0.1:50052 list yaze.test.ImGuiTestHarness
# Describe service
grpcurl -plaintext 127.0.0.1:50052 describe yaze.test.ImGuiTestHarness
API Reference
RPC Service Definition
syntax = "proto3";
package yaze.test;
service ImGuiTestHarness {
rpc Ping(PingRequest) returns (PingResponse);
rpc Click(ClickRequest) returns (ClickResponse);
rpc Type(TypeRequest) returns (TypeResponse);
rpc Wait(WaitRequest) returns (WaitResponse);
rpc Assert(AssertRequest) returns (AssertResponse);
rpc Screenshot(ScreenshotRequest) returns (ScreenshotResponse);
}
Request/Response Schemas
Ping
Request:
{
"message": "string"
}
Response:
{
"message": "string",
"timestampMs": "int64",
"yazeVersion": "string"
}
Click
Request:
{
"target": "button:Name | menu:File→Open | tab:Editor",
"type": "LEFT | RIGHT | MIDDLE | DOUBLE"
}
Response:
{
"success": true,
"message": "Clicked button 'Name'",
"executionTimeMs": "int32"
}
Type
Request:
{
"target": "input:FieldName",
"text": "text to type",
"clear_first": true
}
Response:
{
"success": true,
"message": "Typed 'text' into input 'FieldName'"
}
Wait
Request:
{
"condition": "window_visible:WindowName | element_visible:Label | element_enabled:Label",
"timeout_ms": 5000,
"poll_interval_ms": 100
}
Response:
{
"success": true,
"message": "Condition met after X ms",
"elapsedMs": "int32"
}
Assert
Request:
{
"condition": "visible:Window | enabled:Button | exists:Element | text_contains:Input:ExpectedText"
}
Response:
{
"success": true,
"message": "Assertion passed",
"actualValue": "string",
"expectedValue": "string"
}
Screenshot
Request:
{
"region": "full | window:Name",
"format": "PNG | JPEG"
}
Response:
{
"success": false,
"message": "Screenshot not yet implemented",
"filePath": "",
"fileSizeBytes": 0
}
Resource Catalog Schema
See docs/api/z3ed-resources.yaml for complete machine-readable API specification.
Example Resource:
resources:
- name: rom
description: ROM file operations
actions:
- name: info
description: Display ROM metadata
arguments:
- name: rom
type: string
required: true
description: Path to ROM file
effects:
- Reads ROM file from disk
- Parses ROM header
returns:
- type: object
fields:
- title: string
- size: integer
- checksum: string
Platform Notes
macOS (ARM64) - Production Ready ✅
Status: Fully tested and operational
Build Time: 15-20 minutes (first build), 5-10 seconds (incremental)
Binary Size: ~74 MB (with gRPC)
Known Issues: None
Recommended Setup:
# Use Homebrew for dependencies
brew install cmake grpcurl
# Build with vcpkg (automatic via CMake)
cmake -B build-grpc-test -DYAZE_WITH_GRPC=ON
cmake --build build-grpc-test --target yaze -j$(sysctl -n hw.ncpu)
macOS (Intel) - Should Work ⚠️
Status: Not explicitly tested, but should work
Expected Issues: None (same toolchain as ARM64)
Linux - Should Work ⚠️
Status: Not explicitly tested
Expected Issues: None (gRPC has excellent Linux support)
Setup:
# Install dependencies
sudo apt-get install cmake build-essential
# Build (same as macOS)
cmake -B build-grpc-test -DYAZE_WITH_GRPC=ON
cmake --build build-grpc-test --target yaze -j$(nproc)
Windows - Experimental 🔬
Status: Build system ready, test harness not validated
Known Limitations:
- Test harness not yet tested on Windows
- May require static linking to avoid DLL conflicts
- vcpkg setup more complex than macOS
Recommended Approach: Use Windows Subsystem for Linux (WSL2) for now
Appendix
File Structure
docs/z3ed/
├── E6-z3ed-cli-design.md # Architecture & design (source of truth)
├── E6-z3ed-implementation-plan.md # Implementation tracker & roadmap
├── E6-z3ed-reference.md # This document (technical reference)
├── README.md # Quick overview & links
├── IT-01-QUICKSTART.md # Test harness quick start
├── AGENT_TEST_QUICKREF.md # CLI agent test command reference
├── E2E_VALIDATION_GUIDE.md # Complete validation checklist
├── PROJECT_STATUS_OCT2.md # Current project status
└── archive/ # Historical documentation
Related Documentation
- Build Instructions:
docs/02-build-instructions.md - API Reference:
docs/api/z3ed-resources.yaml - Testing Guide:
docs/A1-testing-guide.md - Contributing:
docs/B1-contributing.md
Version History
- 0.1.0-alpha (Oct 2, 2025) - Initial release
- Resource catalogue complete
- Acceptance workflow operational
- ImGuiTestHarness (IT-01) complete
- CLI agent test (IT-02) complete
- E2E validation 80% complete
Contributors
- @scawful (Project lead, implementation)
- GitHub Copilot (Development assistance, documentation)
License
Same as YAZE - see LICENSE in repository root.
Document Status: Living document, updated as features are added
Last Review: October 2, 2025
Next Review: After Windows testing completion