refactor: make mergegate gate-first

This commit is contained in:
林 駿甫 (Shunsuke Hayashi) 2026-04-10 15:03:49 +09:00
parent 29c72fee83
commit 427b99f400
7 changed files with 239 additions and 2244 deletions

1000
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,6 @@
resolver = "2" resolver = "2"
members = [ members = [
"crates/mergegate-cli", "crates/mergegate-cli",
"crates/mergegate-tui",
"crates/mergegate-core", "crates/mergegate-core",
] ]
@ -14,8 +13,8 @@ authors = ["Miyabi Team"]
license = "BUSL-1.1" license = "BUSL-1.1"
repository = "https://github.com/ShunsukeHayashi/mergegate" repository = "https://github.com/ShunsukeHayashi/mergegate"
homepage = "https://github.com/ShunsukeHayashi/mergegate" homepage = "https://github.com/ShunsukeHayashi/mergegate"
description = "MergeGate - Deterministic task execution and merge workflow for AI-assisted development" description = "MergeGate - Engine-agnostic gate CLI for deterministic task execution in AI-assisted development"
keywords = ["ai", "cli", "tui", "autonomous", "development"] keywords = ["ai", "cli", "workflow", "merge", "development"]
categories = ["command-line-utilities", "development-tools"] categories = ["command-line-utilities", "development-tools"]
[workspace.dependencies] [workspace.dependencies]
@ -24,15 +23,6 @@ tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-std", "syn
futures = "0.3" futures = "0.3"
async-trait = "0.1" async-trait = "0.1"
# TUI Framework
ratatui = { version = "0.29.0", features = [
"scrolling-regions",
"unstable-backend-writer",
"unstable-rendered-line-info",
"unstable-widget-ref",
] }
crossterm = { version = "0.29.0", features = ["bracketed-paste", "event-stream"] }
# Text Processing # Text Processing
textwrap = "0.16" textwrap = "0.16"
unicode-width = "0.2" unicode-width = "0.2"

View file

@ -1,13 +1,22 @@
# MergeGate # MergeGate
Deterministic execution protocol for AI-assisted development. Engine-agnostic gate CLI for AI-assisted development.
Execution layer for GitNexus-style code intelligence: Execution layer for GitNexus-style code intelligence:
- `GitNexus`: understand the codebase - `GitNexus`: understand the codebase
- `MergeGate`: execute changes safely - `MergeGate`: execute changes safely
Current CLI entrypoints: `miyabi` and `mergegate` Core product:
- `mergegate gate ...`
- `miyabi gate ...` (compatibility alias)
- `miyabi tui` / `mergegate tui`: terminal assistant MergeGate is designed to sit in front of Claude Code, Codex, Gemini CLI, and other coding agents. The engine can change. The gate protocol should not.
- `miyabi gate` / `mergegate gate`: deterministic task execution, file locks, and PR/merge workflow
Start with:
```bash
cargo build --release
./target/release/mergegate gate status
./target/release/mergegate gate init
./target/release/mergegate gate guide
```
Start with `cargo build --release`, then run `./target/release/mergegate --help` or `./target/release/mergegate gate guide`.

575
README.md
View file

@ -1,55 +1,68 @@
# MergeGate # MergeGate
MergeGate is a deterministic execution protocol for AI-assisted development. MergeGate is an engine-agnostic gate CLI for AI-assisted development.
It is the execution layer for GitNexus-style code intelligence: GitNexus helps agents understand what will break, and MergeGate makes them execute that work in a safe, verifiable order.
It does not need to be your coding agent, your chat runtime, or your terminal UI. Its job is simpler and more durable:
- register work
- record impact
- lock files
- assign execution
- track branch and PR state
- verify completion
In short: In short:
- `GitNexus`: understand the codebase - `GitNexus`: understand the codebase
- `MergeGate`: execute changes safely - `MergeGate`: execute changes safely
The project currently supports both `miyabi` and `mergegate` as CLI entrypoints. `miyabi` remains the legacy/default command, and `mergegate` is the product-aligned alias. MergeGate is designed to sit in front of coding agents such as Claude Code, Codex, and Gemini CLI. The execution engine can change. The gate protocol should not.
This repository has two common entry points: ## What This Project Is
- `miyabi tui` / `mergegate tui`: interactive terminal assistant MergeGate is a repo workflow tool for deterministic execution.
- `miyabi gate` / `mergegate gate`: deterministic task execution and file-lock workflow for repo work
If you arrived here because of deterministic execution, task locks, PR gates, or agent-safe repo work, start with `mergegate gate` or `miyabi gate`, not the TUI. The core product is:
- `miyabi gate ...`
- `mergegate gate ...`
The binary still supports both `miyabi` and `mergegate` entrypoints today. `mergegate` is the product-aligned command. `miyabi` remains as a compatibility alias.
## 60-Second Setup ## 60-Second Setup
```bash ```bash
# 1. Clone and build
git clone https://github.com/ShunsukeHayashi/mergegate.git git clone https://github.com/ShunsukeHayashi/mergegate.git
cd mergegate cd mergegate
cargo build --release cargo build --release
# 2. Set API key ./target/release/mergegate gate status
export ANTHROPIC_API_KEY="sk-ant-..." ./target/release/mergegate gate init
./target/release/mergegate gate guide
# 3. Run
./target/release/mergegate tui
``` ```
That's it. Start with the TUI, or jump straight into `mergegate gate` for repo workflow control. No API key is required for gate workflow.
---
## Why MergeGate ## Why MergeGate
- **Execution layer for code intelligence** - Pair blast-radius understanding with deterministic execution, not chat-only automation - **Engine agnostic**: Use Claude Code, Codex, Gemini CLI, or another agent runtime
- **Deterministic task execution** - Register, analyze, lock, review, and merge in a verifiable order - **Deterministic execution**: Register, analyze, lock, implement, review, and merge in a verifiable order
- **Repo-safe agent workflow** - File locks and gate checks reduce accidental overlap and unsafe edits - **Repo-safe coordination**: Reduce accidental overlap with file locks and explicit task ownership
- **Interactive TUI** - Terminal assistant for chat, prompts, and agent execution - **Execution ledger**: Keep branch, PR, merge, and completion state tied to actual work
- **Agent mode** - Autonomous execution with tool approval - **Protocol over chat**: The product is the workflow gate, not a built-in assistant
- **Session management** - Persist and resume conversations
- **Configurable** - TOML-based configuration
## Positioning ## Positioning
MergeGate was designed for teams that already believe code understanding is not enough. MergeGate exists because understanding code is not enough.
Knowing the blast radius of a change is only half of the problem. Agents also need a protocol for when work starts, which files are locked, what must be recorded before editing, and what counts as done.
Agents also need a protocol for:
- when a task starts
- which files are locked
- what impact was recorded
- who is implementing
- how branch and PR state are attached
- what counts as done
That is the role split: That is the role split:
@ -63,7 +76,6 @@ If GitNexus answers "what is this change connected to?", MergeGate answers "how
### Prerequisites ### Prerequisites
- Rust 1.70+ - Rust 1.70+
- Anthropic API key
### Build from Source ### Build from Source
@ -77,75 +89,34 @@ Binary will be at `target/release/miyabi` and `target/release/mergegate`.
## Quick Start ## Quick Start
Choose the path that matches what you want to do. ### 1. Check repo status
### A. Use MergeGate as a terminal assistant
Run the TUI after configuring your API key.
#### 1. Generate Config
```bash ```bash
./target/release/miyabi init ./target/release/mergegate gate status
``` ```
This creates `~/.miyabi/config.toml`. If you see `tasks: 0`, the ledger exists and is simply empty.
#### 2. Set API Key ### 2. Initialize gate ledger if needed
Edit `~/.miyabi/config.toml`:
```toml
[api]
api_key = "sk-ant-..."
```
Or use environment variable:
```bash ```bash
export ANTHROPIC_API_KEY="sk-ant-..." ./target/release/mergegate gate init
``` ```
#### 3. Launch TUI This creates `project_memory/tasks.json`.
### 3. Read the built-in workflow guide
```bash ```bash
./target/release/miyabi tui ./target/release/mergegate gate guide
# or simply
./target/release/miyabi
``` ```
### B. Use MergeGate as a task execution gate ### 4. Start a task
If you are working inside a repository and want task registration, impact tracking, file locks, and PR/merge recording, use `mergegate gate` or `miyabi gate`.
#### 1. Check whether the repo is already initialized
```bash ```bash
./target/release/miyabi gate status ./target/release/mergegate gate register --issue 123 --title "Fix login redirect"
``` ./target/release/mergegate gate impact issue-123 --risk medium --symbols 3
./target/release/mergegate gate assign issue-123 --agent codex --node macbook --files "src/auth.rs"
If you see `tasks: 0`, that means the ledger exists but is currently empty.
#### 2. Initialize MergeGate for this repo if needed
```bash
./target/release/miyabi gate init
```
This creates `project_memory/tasks.json` and prepares the repo for gate-managed work.
#### 3. Read the built-in workflow guide
```bash
./target/release/miyabi gate guide
```
#### 4. Start a task
```bash
./target/release/miyabi gate register --issue 123 --title "Fix login redirect"
./target/release/miyabi gate impact issue-123 --risk medium --symbols 3
./target/release/miyabi gate assign issue-123 --agent codex --node macbook --files "src/auth.rs"
``` ```
Typical flow: Typical flow:
@ -153,427 +124,83 @@ Typical flow:
1. `register` 1. `register`
2. `impact` 2. `impact`
3. `assign` 3. `assign`
4. implement 4. implement with your coding agent of choice
5. `branch` 5. `branch`
6. `pr` 6. `pr`
7. `merge` or `manual-complete` 7. `merge` or `manual-complete`
## Usage ## Usage
`MergeGate` is the product and documentation name. ```bash
Both `miyabi` and `mergegate` work today. mergegate gate status
mergegate gate init
mergegate gate guide
mergegate gate register --issue 123 --title "Fix login redirect"
mergegate gate impact issue-123 --risk medium --symbols 3
mergegate gate assign issue-123 --agent codex --node macbook --files "src/auth.rs"
mergegate gate branch issue-123 codex/fix-login-redirect
mergegate gate pr issue-123 456
mergegate gate merge issue-123 <sha>
```
### CLI Commands Compatibility alias:
```bash ```bash
miyabi # Start TUI (default) miyabi gate status
miyabi tui # Start TUI explicitly
miyabi status # Show status
miyabi init # Generate default config
miyabi sessions # List sessions
miyabi sessions -d <id> # Delete session
miyabi sessions -e <id> # Export session to JSON
miyabi version # Show version info
miyabi agent <prompt> # Run autonomous agent
miyabi gate status # Show task ledger status
miyabi gate init # Initialize MergeGate in the current repo
miyabi gate guide # Show the full gate workflow guide
mergegate gate status # Same gate workflow with product-aligned command
mergegate tui # Same TUI with product-aligned command
``` ```
### CLI Options ## Core Commands
```bash ```bash
miyabi --model claude-sonnet-4-5-20250929 # Override model mergegate gate status
miyabi --max-tokens 16384 # Override max tokens mergegate gate init
miyabi --thinking # Enable extended thinking mergegate gate guide
miyabi --config /path/to/config.toml # Custom config mergegate gate register --issue 123 --title "Fix login redirect"
miyabi --session <id> # Resume session mergegate gate assign issue-123 --agent codex --node macbook --files "src/auth.rs"
mergegate gate impact issue-123 --risk medium --symbols 3
mergegate gate branch issue-123 codex/fix-login-redirect
mergegate gate pr issue-123 456
mergegate gate merge issue-123 <sha>
mergegate gate manual-complete issue-123 --reason "docs-only change" --operator shunsuke
mergegate gate locks
mergegate gate dispatchable
mergegate gate dag
``` ```
### TUI Keybindings ## Product Direction
| Key | Action | MergeGate is intentionally moving away from:
|-----|--------|
| `Enter` | Send message |
| `Ctrl+P` | Command palette |
| `F1` | Help |
| `Esc` | Close overlay / Cancel |
| `Ctrl+C` | Quit |
| `j/k` | Scroll down/up |
| `Page Up/Down` | Page scroll |
## Configuration - built-in TUI as the product center
- built-in agent runtime as the product center
- vendor-specific backend identity
Config file: `~/.miyabi/config.toml` The durable surface is the gate CLI.
```toml ## Workspace Layout
[api]
api_key = "sk-ant-..." # Anthropic API key
model = "claude-sonnet-4-5-20250929" # Model to use
max_tokens = 8192 # Max response tokens
thinking = false # Extended thinking
system_prompt = "You are a helpful assistant" # System prompt
timeout_secs = 120 # Request timeout
max_retries = 3 # Retry attempts
[ui] ```text
show_sidebar = false # Show sidebar crates/
show_status_bar = true # Show status bar mergegate-cli/ # CLI entrypoint
show_breadcrumb = true # Show breadcrumb mergegate-core/ # Gate protocol, store, locks, workflow logic
theme = "tokyo-night" # Color theme project_memory/
vim_mode = false # Vim keybindings tasks.json # Execution ledger
show_line_numbers = true # Line numbers in code skills/
mergegate-cli/
[session] mergegate-ops/
auto_save = true # Auto-save sessions
auto_save_interval = 30 # Save interval (seconds)
max_sessions = 100 # Max stored sessions
[tools]
enable_bash = true # Enable bash tool
enable_file_tools = true # Enable file read/write
enable_search_tools = true # Enable glob/grep
auto_approve_low_risk = false # Auto-approve safe tools
bash_timeout = 120 # Bash command timeout
``` ```
### Environment Variables
Override config with environment variables:
```bash
ANTHROPIC_API_KEY=... # API key
MIYABI_MODEL=... # Model name
MIYABI_MAX_TOKENS=... # Max tokens
MIYABI_THINKING=true # Enable thinking
```
## Agent Mode
Run autonomous tasks with tool execution:
```bash
# Basic usage
miyabi agent "Create a hello world Python script"
# With options
miyabi agent "Refactor the utils module" \
--max-iterations 20 \
--auto-approve \
--system "You are an expert Rust developer"
```
Agent mode features:
- Autonomous tool execution (bash, file operations, search)
- Approval workflow for risky operations
- Iteration limits for safety
- JSON output format option
## Core Library Features
The `mergegate-core` crate provides powerful utilities for building AI applications.
### Git Utilities
```rust
use miyabi_core::{find_git_root, get_current_branch, is_in_git_repo};
// Find repository root
let root = find_git_root()?;
// Get current branch
let branch = get_current_branch(&root)?;
// Check if in git repo
if is_in_git_repo(&path) {
println!("In a git repository");
}
```
### Logger System
```rust
use miyabi_core::{init_logger, LogLevel, LogFormat};
// Initialize with defaults
init_logger();
// Or with custom config
use miyabi_core::LoggerConfig;
let config = LoggerConfig {
level: LogLevel::Debug,
format: LogFormat::Json,
..Default::default()
};
init_logger_with_config(config);
```
### Retry with Backoff
```rust
use miyabi_core::{retry_with_backoff, BackoffRetryConfig};
let config = BackoffRetryConfig::default();
let result = retry_with_backoff(config, || async {
// Your operation that might fail
make_api_call().await
}).await?;
```
### Circuit Breaker
```rust
use miyabi_core::{CircuitBreaker, CircuitState};
let breaker = CircuitBreaker::default();
let result = breaker.call(|| {
Box::pin(async {
// Your operation
Ok::<_, std::io::Error>(())
})
}).await;
// Check state
match breaker.state().await {
CircuitState::Closed => println!("Normal operation"),
CircuitState::Open => println!("Circuit open - blocking calls"),
CircuitState::HalfOpen => println!("Testing recovery"),
}
```
### Rules System (.miyabirules)
Support for project-specific rules via `.miyabirules` files:
```yaml
# .miyabirules
version: 1
rules:
- name: "no-unwrap"
pattern: ".unwrap()"
suggestion: "Use ? operator or proper error handling"
file_extensions: ["rs"]
severity: "warning"
agent_preferences:
codegen:
style: "functional"
error_handling: "result"
```
```rust
use miyabi_core::{RulesLoader, MiyabiRules};
let loader = RulesLoader::new(project_root);
let rules = loader.load_or_default()?;
// Get rules for a file
let applicable = rules.rules_for_file(Path::new("src/main.rs"));
```
### Cache System
```rust
use miyabi_core::{create_llm_cache, create_api_cache, LLMCacheKey};
// LLM response cache (1 hour TTL)
let cache = create_llm_cache();
let key = LLMCacheKey::new("prompt", "model", Some(0.7));
cache.insert(key.clone(), "response".to_string()).await;
let cached = cache.get(&key).await;
// API cache (30 min TTL)
let api_cache = create_api_cache();
```
### Plugin System
```rust
use miyabi_core::{Plugin, PluginManager, PluginMetadata, PluginContext, PluginResult};
use anyhow::Result;
struct MyPlugin;
impl Plugin for MyPlugin {
fn metadata(&self) -> PluginMetadata {
PluginMetadata {
name: "my-plugin".to_string(),
version: "1.0.0".to_string(),
description: Some("My custom plugin".to_string()),
author: None,
}
}
fn init(&mut self) -> Result<()> {
Ok(())
}
fn execute(&self, ctx: &PluginContext) -> Result<PluginResult> {
Ok(PluginResult {
success: true,
message: Some("Done".to_string()),
data: None,
})
}
}
// Register and execute
let manager = PluginManager::new();
manager.register(Box::new(MyPlugin))?;
let result = manager.execute("my-plugin", &PluginContext::default())?;
```
### Feature Flags
```rust
use miyabi_core::{FeatureFlagManager, FeatureFlag};
let flags = FeatureFlagManager::new();
// Simple flag
flags.set_flag("new_feature", true);
if flags.is_enabled("new_feature") {
// Use new feature
}
// With rollout percentage
flags.set_flag_with_options(
"beta_feature",
true,
Some("Beta testing".to_string()),
Some(0.5), // 50% rollout
);
// Load from config
use std::collections::HashMap;
let mut config = HashMap::new();
config.insert("flag1".to_string(), true);
flags.load_from_map(config);
```
## Project Structure
```
mergegate/
├── crates/
│ ├── mergegate-cli/ # CLI entry point
│ ├── mergegate-core/ # Core library
│ │ ├── agent.rs # Agent system
│ │ ├── anthropic.rs # Anthropic API client
│ │ ├── cache.rs # TTL cache system
│ │ ├── config.rs # Configuration
│ │ ├── error_policy.rs # Circuit breaker
│ │ ├── feature_flags.rs # Feature flag management
│ │ ├── git.rs # Git utilities
│ │ ├── logger.rs # Logging system
│ │ ├── plugin.rs # Plugin system
│ │ ├── retry.rs # Retry with backoff
│ │ ├── rules.rs # .miyabirules support
│ │ ├── session.rs # Session management
│ │ ├── tools.rs # Built-in tools
│ │ └── ...
│ └── mergegate-tui/ # TUI implementation
│ ├── app.rs # Main application
│ ├── views.rs # UI views
│ └── ...
├── .miyabi/ # Local config
├── Cargo.toml # Workspace config
└── README.md
```
## Development
### Build
```bash
cargo build # Debug build
cargo build --release # Release build
```
### Test
```bash
cargo test --all # Run all tests
```
### Lint
```bash
cargo clippy --all-targets -- -D warnings
cargo fmt --all --check
```
## Models
Supported models:
- `claude-sonnet-4-5-20250929` (default)
- `claude-haiku-4-5-20251001`
- `claude-sonnet-4-20250514`
## Troubleshooting ## Troubleshooting
### Common Issues ### `gate status` says `tasks: 0`
#### "API key not found" That is not an error. It means the ledger exists but no tasks have been registered yet.
```bash
# Check if environment variable is set
echo $ANTHROPIC_API_KEY
# Or add to config file ### `gate init` says the project is already initialized
vim ~/.miyabi/config.toml
# [api]
# api_key = "sk-ant-..."
```
#### "Device not configured" error on TUI start That is usually safe. It means `project_memory/tasks.json` already exists.
This usually means the terminal doesn't support the required features. Try:
```bash
# Use a different terminal emulator (iTerm2, Alacritty, etc.)
# Or run with explicit terminal type
TERM=xterm-256color ./target/release/miyabi tui
```
#### Build errors ### I want to use another coding agent
```bash
# Make sure Rust is up to date
rustup update
# Clean and rebuild That is the intended model. MergeGate is the gate, not the engine.
cargo clean
cargo build --release
```
#### Session not saving
```bash
# Check permissions on sessions directory
ls -la ~/.miyabi/sessions/
# Create if missing
mkdir -p ~/.miyabi/sessions
```
### Debug Mode
For verbose logging:
```bash
RUST_LOG=debug ./target/release/miyabi tui
```
### Getting Help
- Check `miyabi --help` for CLI options
- Press `F1` in TUI for keybindings
- Open an issue: https://github.com/ShunsukeHayashi/mergegate/issues
## License
MIT
---
Built with Rust, Ratatui, and Claude API.

View file

@ -7,7 +7,7 @@ authors.workspace = true
license.workspace = true license.workspace = true
repository.workspace = true repository.workspace = true
homepage.workspace = true homepage.workspace = true
description = "MergeGate CLI - Main command-line interface for deterministic task execution and agent-assisted development" description = "MergeGate CLI - Engine-agnostic gate workflow for deterministic task execution"
[[bin]] [[bin]]
name = "miyabi" name = "miyabi"
@ -20,15 +20,10 @@ path = "src/bin/mergegate.rs"
[dependencies] [dependencies]
# Workspace crates # Workspace crates
miyabi-core = { package = "mergegate-core", path = "../mergegate-core" } miyabi-core = { package = "mergegate-core", path = "../mergegate-core" }
miyabi-tui = { package = "mergegate-tui", path = "../mergegate-tui" }
# CLI # CLI
clap = { workspace = true } clap = { workspace = true }
# TUI Framework
ratatui = { workspace = true }
crossterm = { workspace = true }
# Async Runtime # Async Runtime
tokio = { workspace = true } tokio = { workspace = true }

View file

@ -62,36 +62,14 @@ fn agent_guide() -> String {
} }
#[derive(Parser)] #[derive(Parser)]
#[command(author, version, about = "MergeGate - Deterministic task execution and merge workflow for AI-assisted development", long_about = None)] #[command(author, version, about = "MergeGate - Engine-agnostic gate CLI for AI-assisted development", long_about = None)]
struct Cli { struct Cli {
/// Model to use (overrides config)
#[arg(short, long)]
model: Option<String>,
/// Maximum tokens for responses (overrides config)
#[arg(long)]
max_tokens: Option<u32>,
/// Enable Extended Thinking (Claude 4.5+)
#[arg(long)]
thinking: bool,
/// Path to config file
#[arg(short, long)]
config: Option<PathBuf>,
/// Session ID to load on startup
#[arg(short, long)]
session: Option<String>,
#[command(subcommand)] #[command(subcommand)]
command: Option<Commands>, command: Option<Commands>,
} }
#[derive(Subcommand)] #[derive(Subcommand)]
enum Commands { enum Commands {
/// Start the TUI interface
Tui,
/// Show status /// Show status
Status, Status,
/// Generate default config file /// Generate default config file
@ -116,23 +94,6 @@ enum Commands {
#[arg(short, long)] #[arg(short, long)]
verbose: bool, verbose: bool,
}, },
/// Run agent with a prompt (autonomous execution)
Agent {
/// The prompt to execute
prompt: String,
/// Maximum iterations (default: 10)
#[arg(long, default_value = "10")]
max_iterations: usize,
/// Auto-approve all tool executions
#[arg(long)]
auto_approve: bool,
/// Output format: text or json
#[arg(long, default_value = "text")]
format: String,
/// System prompt for the agent
#[arg(long)]
system: Option<String>,
},
#[command( #[command(
about = "Deterministic Task Protocol gate controls", about = "Deterministic Task Protocol gate controls",
long_about = "Run the gate init command to set up a new project.\n\nDeterministic Task Protocol gate controls" long_about = "Run the gate init command to set up a new project.\n\nDeterministic Task Protocol gate controls"
@ -452,78 +413,35 @@ async fn main() -> anyhow::Result<()> {
let cli = Cli::from_arg_matches(&matches).unwrap_or_else(|error| error.exit()); let cli = Cli::from_arg_matches(&matches).unwrap_or_else(|error| error.exit());
match cli.command { match cli.command {
Some(Commands::Tui) | None => { None => {
// Run TUI let mut command = Cli::command();
use crossterm::{ command = command.name(current_binary_name());
event::{DisableMouseCapture, EnableMouseCapture}, command.print_help()?;
execute, println!();
terminal::{ println!();
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, println!("Start here:");
}, println!(" {}", gate_command("status"));
}; println!(" {}", gate_command("init"));
use miyabi_core::config::Config; println!(" {}", gate_command("guide"));
use miyabi_tui::App;
use ratatui::prelude::*;
use std::io;
// Load config (from custom path or default)
let mut config = if let Some(config_path) = &cli.config {
Config::load_from(config_path)?
} else {
Config::load().unwrap_or_default()
};
// Apply CLI overrides
if let Some(model) = &cli.model {
config.api.model = model.clone();
}
if let Some(max_tokens) = cli.max_tokens {
config.api.max_tokens = max_tokens;
}
if cli.thinking {
config.api.thinking = true;
}
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let mut app = App::with_config(config);
// Load session if specified
if let Some(session_id) = &cli.session {
if let Err(e) = app.load_session(session_id) {
eprintln!("Warning: Failed to load session {}: {}", session_id, e);
}
}
let res = app.run(&mut terminal).await;
disable_raw_mode()?;
execute!(
terminal.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
)?;
terminal.show_cursor()?;
if let Err(err) = res {
eprintln!("Error: {}", err);
}
} }
Some(Commands::Status) => { Some(Commands::Status) => {
use miyabi_core::config::Config; use miyabi_core::config::Config;
let config = Config::load().unwrap_or_default(); let config = Config::load().unwrap_or_default();
println!("Miyabi Status: Ready"); println!("MergeGate Status: Ready");
println!(); println!();
println!("Binary: {}", current_binary_name());
println!("Config: {}", Config::default_path().display()); println!("Config: {}", Config::default_path().display());
println!("Sessions: {}", config.sessions_dir().display());
println!("Model: {}", config.api.model);
println!(); println!();
println!("Core workflow:");
println!(" {}", gate_command("status"));
println!(" {}", gate_command("init"));
println!(" {}", gate_command("guide"));
println!();
println!("Direct runtime config remains on disk for compatibility.");
println!("Model: {}", config.api.model);
println!("Sessions: {}", config.sessions_dir().display());
// Load and show rules info // Load and show rules info
let cwd = std::env::current_dir().unwrap_or_default(); let cwd = std::env::current_dir().unwrap_or_default();
@ -766,152 +684,6 @@ async fn main() -> anyhow::Result<()> {
} }
} }
} }
Some(Commands::Agent {
prompt,
max_iterations,
auto_approve,
format,
system,
}) => {
use miyabi_core::{
config::Config, Agent, AgentConfig, AgentEvent, AnthropicClient, ExecutorRegistry,
};
use tokio::sync::mpsc;
// Load config
let mut config = if let Some(config_path) = &cli.config {
Config::load_from(config_path)?
} else {
Config::load().unwrap_or_default()
};
// Apply CLI overrides
if let Some(model) = &cli.model {
config.api.model = model.clone();
}
if let Some(max_tokens) = cli.max_tokens {
config.api.max_tokens = max_tokens;
}
if cli.thinking {
config.api.thinking = true;
}
// Get API key
let api_key = config
.api
.api_key
.clone()
.or_else(|| std::env::var("ANTHROPIC_API_KEY").ok())
.ok_or_else(|| {
anyhow::anyhow!("No API key found. Set ANTHROPIC_API_KEY or add to config.")
})?;
// Create client
let client = AnthropicClient::new(api_key)?
.with_model(&config.api.model)
.with_max_tokens(config.api.max_tokens)
.with_thinking(config.api.thinking);
// Create executor registry with standard tools
let registry = ExecutorRegistry::with_standard_tools();
// Configure agent
let agent_config = AgentConfig {
max_iterations,
max_tokens_per_turn: config.api.max_tokens,
require_approval: !auto_approve,
auto_approve_patterns: if auto_approve {
vec![
"read".to_string(),
"glob".to_string(),
"grep".to_string(),
"write".to_string(),
"edit".to_string(),
"bash".to_string(),
]
} else {
vec!["read".to_string(), "glob".to_string(), "grep".to_string()]
},
..Default::default()
};
// Create agent
let mut agent = Agent::new(client, registry).with_config(agent_config);
// Set system prompt
if let Some(sys) = system {
agent = agent.with_system_prompt(sys);
} else if let Some(sys) = config.api.system_prompt {
agent = agent.with_system_prompt(sys);
}
// Create event channel for progress
let (tx, mut rx) = mpsc::channel(100);
let agent = agent.with_event_channel(tx);
// Spawn agent execution
let agent_handle = tokio::spawn(async move { agent.run(&prompt).await });
// Process events
while let Some(event) = rx.recv().await {
match &event {
AgentEvent::Started { prompt } => {
if format != "json" {
eprintln!("🚀 Agent started with prompt: {}", truncate_str(prompt, 50));
}
}
AgentEvent::Thinking { iteration } => {
if format != "json" {
eprintln!("💭 Iteration {}", iteration + 1);
}
}
AgentEvent::ToolDetected { name, .. } => {
if format != "json" {
eprintln!("🔧 Tool detected: {}", name);
}
}
AgentEvent::ToolExecuting { name, .. } => {
if format != "json" {
eprintln!("⚡ Executing: {}", name);
}
}
AgentEvent::ToolCompleted { name, .. } => {
if format != "json" {
eprintln!("✅ Completed: {}", name);
}
}
AgentEvent::ToolFailed { name, error } => {
if format != "json" {
eprintln!("❌ Failed {}: {}", name, error);
}
}
AgentEvent::Completed { result } => {
if format == "json" {
println!("{}", serde_json::to_string_pretty(&result)?);
} else {
println!("\n{}", result.output);
eprintln!(
"\n📊 Stats: {} iterations, {} tool calls, {} tokens",
result.iterations, result.tool_calls, result.total_tokens
);
}
}
AgentEvent::Failed { error } => {
eprintln!("❌ Agent failed: {}", error);
}
_ => {}
}
}
// Wait for agent to complete
match agent_handle.await? {
Ok(_) => {}
Err(e) => {
eprintln!("Agent error: {}", e);
std::process::exit(1);
}
}
}
Some(Commands::Gate { Some(Commands::Gate {
format, format,
emit_event, emit_event,

View file

@ -1,578 +1,172 @@
# MergeGate ユーザーマニュアル # MergeGate ユーザーマニュアル
**Version**: 0.1.0 **Version**: 0.1.0
**Last Updated**: 2025-11-23 **Last Updated**: 2026-04-10
---
## 目次
1. [はじめに](#はじめに)
2. [インストール](#インストール)
3. [初期設定](#初期設定)
4. [基本的な使い方](#基本的な使い方)
5. [TUIモード](#tuiモード)
6. [Agentモード](#agentモード)
7. [セッション管理](#セッション管理)
8. [設定ファイル](#設定ファイル)
9. [プロジェクトルール](#プロジェクトルール)
10. [トラブルシューティング](#トラブルシューティング)
---
## はじめに ## はじめに
MergeGate は、AI-assisted development 向けの deterministic task execution and merge workflow です。CLI では `miyabi``mergegate` の両方を使え、対話型の TUI と `gate` ベースの repo workflow を提供します。 MergeGate は、AI-assisted development 向けの engine-agnostic gate CLI です。
設計思想はシンプルです。 このツールはエージェント本体ではありません。TUI や direct backend を前提にせず、repo 作業を安全に進めるための protocol を提供します。
役割は次の通りです。
- task を登録する
- impact を記録する
- file lock を取る
- branch / PR / merge 状態を結び付ける
- completion を記録する
設計思想:
- `GitNexus`: コードベースを理解する - `GitNexus`: コードベースを理解する
- `MergeGate`: 変更を安全に実行する - `MergeGate`: 変更を安全に実行する
影響範囲が分かるだけでは、AI エージェントは安全に開発できません。どの task を登録し、どのファイルを lock し、どの順序で branch / PR / merge まで進めるかを protocol として固定するのが MergeGate の役割です。 ## 何をするツールか
### 主な機能 MergeGate の中心機能は `gate` です。
- **TUIモード**: 美しいターミナルUIでの対話 ```bash
- **Agentモード**: ファイル操作やコマンド実行を含む自律実行 mergegate gate ...
- **セッション管理**: 会話履歴の保存・再開 ```
- **プロジェクトルール**: .miyabirulesによるカスタムルール
--- または互換 alias として:
```bash
miyabi gate ...
```
実行エンジンは Claude Code、Codex、Gemini CLI など、どれでも構いません。MergeGate はその前後で repo workflow を制御します。
## インストール ## インストール
### 必要要件 ### 必要要件
- Rust 1.70以上 - Rust 1.70以上
- Anthropic APIキー
### ビルド手順 ### ビルド
```bash ```bash
# 1. リポジトリをクローン
git clone https://github.com/ShunsukeHayashi/mergegate.git git clone https://github.com/ShunsukeHayashi/mergegate.git
cd mergegate cd mergegate
# 2. リリースビルド
cargo build --release cargo build --release
# 3. バイナリの確認
ls -la target/release/miyabi target/release/mergegate
``` ```
### パスを通す(オプション) ## 最初にやること
### 1. repo の状態確認
```bash ```bash
# ~/.bashrc または ~/.zshrc に追加 ./target/release/mergegate gate status
export PATH="$PATH:/path/to/mergegate/target/release"
# 設定を反映
source ~/.bashrc # または source ~/.zshrc
``` ```
--- `tasks: 0` は正常です。ledger はあるが task がまだ無い状態です。
## 初期設定 ### 2. 初期化
### 1. 設定ファイルの生成
```bash ```bash
./target/release/miyabi init ./target/release/mergegate gate init
``` ```
これにより `~/.miyabi/config.toml` が作成されます。 これ`project_memory/tasks.json` が作成されます。
### 2. APIキーの設定 ### 3. ガイド確認
**方法1: 環境変数(推奨)**
```bash
export ANTHROPIC_API_KEY="sk-ant-api03-..."
```
永続化する場合は `~/.bashrc``~/.zshrc` に追加:
```bash
echo 'export ANTHROPIC_API_KEY="sk-ant-api03-..."' >> ~/.zshrc
```
**方法2: 設定ファイル**
```bash
vim ~/.miyabi/config.toml
```
```toml
[api]
api_key = "sk-ant-api03-..."
```
### 3. 設定の確認
```bash ```bash
./target/release/miyabi status ./target/release/mergegate gate guide
``` ```
出力例: ## 基本フロー
```
Miyabi Status: Ready
Config: /Users/you/.miyabi/config.toml ```bash
Sessions: /Users/you/.miyabi/sessions ./target/release/mergegate gate register --issue 123 --title "Fix login redirect"
Model: claude-sonnet-4-5-20250929 ./target/release/mergegate gate impact issue-123 --risk medium --symbols 3
./target/release/mergegate gate assign issue-123 --agent codex --node macbook --files "src/auth.rs"
Rules: 0 rules loaded ./target/release/mergegate gate branch issue-123 codex/fix-login-redirect
./target/release/mergegate gate pr issue-123 456
./target/release/mergegate gate merge issue-123 <sha>
``` ```
--- 典型的な順番:
## 基本的な使い方 1. `register`
2. `impact`
3. `assign`
4. 実装
5. `branch`
6. `pr`
7. `merge` または `manual-complete`
### コマンド一覧 ## コマンド一覧
| コマンド | 説明 | | コマンド | 説明 |
|---------|------| |---------|------|
| `miyabi tui` | TUIモードを起動 | | `mergegate gate status` | ledger 全体または task 状態を表示 |
| `miyabi agent <prompt>` | Agentモードで実行 | | `mergegate gate init` | ledger を初期化 |
| `miyabi status` | ステータス表示 | | `mergegate gate guide` | workflow ガイドを表示 |
| `miyabi version` | バージョン情報 | | `mergegate gate register` | task を登録 |
| `miyabi init` | 設定ファイル生成 | | `mergegate gate impact` | impact を記録 |
| `miyabi sessions` | セッション一覧 | | `mergegate gate assign` | task を割り当てて lock を取得 |
| `miyabi rules` | プロジェクトルール表示 | | `mergegate gate branch` | branch を記録 |
| `mergegate gate pr` | PR 番号を記録 |
| `mergegate gate merge` | merge を記録 |
| `mergegate gate manual-complete` | 手動完了を記録 |
| `mergegate gate locks` | active lock を表示 |
| `mergegate gate dispatchable` | 今着手できる task を表示 |
| `mergegate gate dag` | 依存順序を表示 |
### グローバルオプション ## 実行エンジンとの関係
| オプション | 説明 | MergeGate は coding agent を置き換えるものではありません。
|-----------|------|
| `-m, --model <MODEL>` | 使用するモデルを指定 |
| `--max-tokens <N>` | 最大トークン数 |
| `--thinking` | Extended Thinking有効化 |
| `-c, --config <PATH>` | 設定ファイルパス |
| `-s, --session <ID>` | セッションID指定 |
### 使用例 想定している使い方:
```bash - Claude Code が実装する
# バージョン確認 - Codex が実装する
./target/release/miyabi version - Gemini CLI が実装する
- MergeGate が task / lock / merge discipline を管理する
# ステータス確認 つまり:
./target/release/miyabi status
# モデル指定でTUI起動 - エージェントは交換可能
./target/release/miyabi tui --model claude-sonnet-4-5-20250929 - gate protocol は固定
# Extended Thinking有効でTUI起動 ## よくある質問
./target/release/miyabi tui --thinking
```
--- ### API キーは必要ですか
## TUIモード `gate` workflow だけなら不要です。
### 起動 ### TUI は必要ですか
```bash 不要です。MergeGate の本体ではありません。
./target/release/miyabi tui
```
### キーバインド ### built-in backend は必要ですか
#### 基本操作 不要です。MergeGate の本体ではありません。
| キー | 動作 | ### `miyabi``mergegate` のどちらを使えばいいですか
|------|------|
| `Enter` | メッセージ送信 |
| `Ctrl+C` | 終了 |
| `Esc` | オーバーレイを閉じる / キャンセル |
| `F1` | ヘルプ表示 |
#### ナビゲーション 新規利用では `mergegate` を推奨します。`miyabi` は互換 alias です。
| キー | 動作 |
|------|------|
| `j` / `↓` | 下にスクロール |
| `k` / `↑` | 上にスクロール |
| `Page Down` | ページ下へ |
| `Page Up` | ページ上へ |
| `g` | 先頭へ |
| `G` | 末尾へ |
#### コマンド
| キー | 動作 |
|------|------|
| `Ctrl+P` | コマンドパレット |
| `Ctrl+N` | 新規セッション |
| `Ctrl+O` | セッションを開く |
| `Ctrl+S` | セッション保存 |
### Vimモード
設定で有効化できます:
```toml
[ui]
vim_mode = true
```
有効にすると、テキスト入力でVimキーバインドが使用可能になります。
---
## Agentモード
Agentモードは、プロンプトに基づいて自律的にタスクを実行します。
### 基本使用
```bash
./target/release/miyabi agent "タスクの説明"
```
### オプション
| オプション | 説明 | デフォルト |
|-----------|------|-----------|
| `--max-iterations <N>` | 最大イテレーション数 | 10 |
| `--auto-approve` | ツール実行を自動承認 | false |
| `--format <FORMAT>` | 出力形式 (text/json) | text |
| `--system <PROMPT>` | システムプロンプト | なし |
### 使用例
```bash
# 基本的な実行
./target/release/miyabi agent "Create a Python script that prints hello world"
# 自動承認モード(注意して使用)
./target/release/miyabi agent --auto-approve "List all .rs files in src/"
# イテレーション数を増やす
./target/release/miyabi agent --max-iterations 20 "Refactor the utils module"
# JSON出力
./target/release/miyabi agent --format json "Show current directory"
# カスタムシステムプロンプト
./target/release/miyabi agent --system "You are an expert Rust developer" "Review main.rs"
```
### 利用可能なツール
Agentモードでは以下のツールが使用可能です
- **Bash**: シェルコマンドの実行
- **Read**: ファイルの読み取り
- **Write**: ファイルの書き込み
- **Edit**: ファイルの編集
- **Glob**: ファイルパターン検索
- **Grep**: テキスト検索
### セキュリティ
- デフォルトでは危険な操作は承認を求められます
- `--auto-approve` は信頼できるタスクのみに使用してください
- `--max-iterations` で無限ループを防止
---
## セッション管理
### セッション一覧の表示
```bash
./target/release/miyabi sessions
```
出力例:
```
ID Title Messages Tokens Updated
------------------------------------------------------------------------------------------
133b91bf-99c9-4097-974c-c60c9abd2495 test 6 246 2025-11-22 14:36
19af5958-183f-4b39-be2e-b14b0809181c test 2 21 2025-11-22 14:03
```
### セッションの操作
```bash
# セッションを削除
./target/release/miyabi sessions -d <session-id>
# JSONにエクスポート
./target/release/miyabi sessions -e <session-id>
# Markdownにエクスポート
./target/release/miyabi sessions -m <session-id>
```
### セッションの再開
```bash
# 特定のセッションからTUIを起動
./target/release/miyabi tui -s <session-id>
```
### 保存場所
セッションは `~/.miyabi/sessions/` に保存されます。
---
## 設定ファイル
### 設定ファイルの場所
```
~/.miyabi/config.toml
```
### 完全な設定例
```toml
[api]
# Anthropic APIキー環境変数ANTHROPIC_API_KEYでも設定可能
api_key = "sk-ant-api03-..."
# 使用するモデル
model = "claude-sonnet-4-5-20250929"
# 最大トークン数
max_tokens = 8192
# Extended ThinkingClaude 4.5+
thinking = false
# システムプロンプト
system_prompt = "You are a helpful AI assistant."
# リクエストタイムアウト(秒)
timeout_secs = 120
# 最大リトライ回数
max_retries = 3
[ui]
# サイドバー表示
show_sidebar = false
# ステータスバー表示
show_status_bar = true
# パンくずリスト表示
show_breadcrumb = true
# カラーテーマ
theme = "tokyo-night"
# Vimモード
vim_mode = false
# コードブロックの行番号
show_line_numbers = true
[session]
# セッションの自動保存
auto_save = true
# 自動保存間隔(秒)
auto_save_interval = 30
# 最大セッション数
max_sessions = 100
[tools]
# Bashツールを有効化
enable_bash = true
# ファイルツールread/write/editを有効化
enable_file_tools = true
# 検索ツールglob/grepを有効化
enable_search_tools = true
# 低リスクツールの自動承認
auto_approve_low_risk = false
# Bashコマンドのタイムアウト
bash_timeout = 120
```
### 環境変数による上書き
| 環境変数 | 説明 |
|---------|------|
| `ANTHROPIC_API_KEY` | APIキー |
| `MIYABI_MODEL` | モデル名 |
| `MIYABI_MAX_TOKENS` | 最大トークン数 |
| `MIYABI_THINKING` | Extended Thinking (true/false) |
---
## プロジェクトルール
### .miyabirulesファイル
プロジェクトルートに `.miyabirules` ファイルを作成することで、プロジェクト固有のルールを定義できます。
### ファイル形式
```yaml
version: 1
rules:
- name: "no-unwrap"
pattern: ".unwrap()"
suggestion: "Use ? operator or proper error handling"
file_extensions: ["rs"]
severity: "warning"
- name: "no-println-debug"
pattern: "println!"
suggestion: "Use tracing macros for logging"
file_extensions: ["rs"]
severity: "info"
agent_preferences:
codegen:
style: "functional"
error_handling: "result"
min_score: 80
review:
min_score: 70
```
### ルールの確認
```bash
./target/release/miyabi rules
```
### 重要度レベル
| レベル | 説明 |
|--------|------|
| `error` | 重大な問題(赤) |
| `warning` | 警告(黄) |
| `info` | 情報(青) |
---
## トラブルシューティング ## トラブルシューティング
### "API key not found" エラー ### `tasks: 0`
異常ではありません。task が未登録なだけです。
### どの task から始めればよいか分からない
```bash ```bash
# 環境変数を確認 ./target/release/mergegate gate dispatchable
echo $ANTHROPIC_API_KEY ./target/release/mergegate gate dag
./target/release/mergegate gate guide
# 設定されていない場合
export ANTHROPIC_API_KEY="sk-ant-..."
``` ```
### "Device not configured" エラー ### 既存 repo に導入済みか分からない
ターミナルがTUIをサポートしていない可能性があります
```bash ```bash
# 別のターミナルを試すiTerm2, Alacritty等 ./target/release/mergegate gate status
# または明示的にTERM設定
TERM=xterm-256color ./target/release/miyabi tui
``` ```
### ビルドエラー ledger が無ければ `gate init` に進めます。
```bash
# Rustを最新版に更新
rustup update
# クリーンビルド
cargo clean
cargo build --release
```
### セッションが保存されない
```bash
# ディレクトリの確認
ls -la ~/.miyabi/sessions/
# なければ作成
mkdir -p ~/.miyabi/sessions
```
### デバッグモード
詳細なログを表示:
```bash
RUST_LOG=debug ./target/release/miyabi tui
```
### ネットワークエラー
```bash
# タイムアウトを延長
# ~/.miyabi/config.toml
[api]
timeout_secs = 300
max_retries = 5
```
---
## サポート
### ヘルプの確認
```bash
# 全体のヘルプ
./target/release/miyabi --help
# サブコマンドのヘルプ
./target/release/miyabi agent --help
./target/release/miyabi sessions --help
```
### 問題報告
GitHub Issues: https://github.com/ShunsukeHayashi/mergegate/issues
### TUIでのヘルプ
TUI起動中に `F1` キーでヘルプを表示できます。
---
## 付録
### 対応モデル
- `claude-sonnet-4-5-20250929` (デフォルト)
- `claude-haiku-4-5-20251001`
- `claude-sonnet-4-20250514`
### ファイル構成
```
~/.miyabi/
├── config.toml # 設定ファイル
└── sessions/ # セッションデータ
├── xxx.json
└── yyy.json
```
### ショートカット早見表
| 操作 | キー |
|------|------|
| 送信 | Enter |
| 終了 | Ctrl+C |
| ヘルプ | F1 |
| コマンドパレット | Ctrl+P |
| 新規セッション | Ctrl+N |
| セッションを開く | Ctrl+O |
| 保存 | Ctrl+S |
---
**Built with Rust, Ratatui, and Claude API**