agentchrome 1.62.0

A CLI tool for browser automation via the Chrome DevTools Protocol
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
# Design: CLI Skeleton with Clap Derive Macros

**Issues**: #3
**Date**: 2026-02-10
**Status**: Draft
**Author**: Claude (spec-driven)

---

## Overview

This feature replaces the current `main.rs` (which only prints version info) with a full clap-based CLI skeleton. The implementation introduces argument parsing via clap derive macros, 13 subcommand group stubs, global connection/output options, structured JSON error output, and exit code conventions.

The design follows the planned project structure from `structure.md`, placing CLI parsing in `src/cli/` and error types in `src/error.rs`. Each subcommand is a stub that returns a "not yet implemented" error in structured JSON format on stderr.

Since this is a CLI-only feature with no backend, CDP, or Chrome process management, the scope is limited to the CLI and Output layers.

---

## Architecture

### Component Diagram

```
CLI Input (args)
┌─────────────────────────────────────────────────────┐
│   main.rs                                           │
│   - Create Cli struct via clap::Parser::parse()     │
│   - Match on Command enum                           │
│   - Dispatch to stub handlers                       │
│   - Handle errors via process::exit()               │
└────────────────────┬────────────────────────────────┘
          ┌──────────┼──────────┐
          ↓          ↓          ↓
┌──────────────┐ ┌────────┐ ┌───────────┐
│  cli/mod.rs  │ │error.rs│ │output (*)│
│  - Cli struct│ │- ExitCode│ │- JSON err │
│  - Command   │ │- AppError│ │  to stderr│
│  - GlobalOpts│ │         │ │           │
│  - OutputFmt │ │         │ │           │
└──────────────┘ └────────┘ └───────────┘

(*) Output formatting is minimal in this issue —
    only structured JSON error output to stderr.
    A full output layer comes in later issues.
```

### Data Flow

```
1. User runs: agentchrome [global-opts] <subcommand>
2. clap parses args into Cli struct
3. main() matches on Cli.command
4. Stub handler returns AppError::NotImplemented
5. Error is serialized to JSON on stderr
6. Process exits with appropriate exit code
```

---

## Module Design

### `src/cli/mod.rs` — CLI Argument Parsing

The core clap structs using derive macros:

```rust
#[derive(Parser)]
#[command(
    name = "agentchrome",
    version,
    about = "Browser automation via the Chrome DevTools Protocol",
    long_about = "...",  // Comprehensive AI-agent-friendly description
    term_width = 100,
)]
pub struct Cli {
    #[command(flatten)]
    pub global: GlobalOpts,

    #[command(subcommand)]
    pub command: Command,
}
```

#### Global Options (flattened via `#[command(flatten)]`)

```rust
#[derive(Args)]
pub struct GlobalOpts {
    // Connection options
    #[arg(long, default_value = "9222", global = true, help = "...")]
    pub port: u16,

    #[arg(long, default_value = "127.0.0.1", global = true, help = "...")]
    pub host: String,

    #[arg(long, global = true, help = "...")]
    pub ws_url: Option<String>,

    #[arg(long, global = true, help = "...")]
    pub timeout: Option<u64>,

    #[arg(long, global = true, help = "...")]
    pub tab: Option<String>,

    // Output format (mutually exclusive group)
    #[command(flatten)]
    pub output: OutputFormat,
}
```

#### Output Format (mutually exclusive group)

```rust
#[derive(Args)]
#[group(multiple = false)]
pub struct OutputFormat {
    #[arg(long, global = true, help = "Output as JSON (default)")]
    pub json: bool,

    #[arg(long, global = true, help = "Output as pretty-printed JSON")]
    pub pretty: bool,

    #[arg(long, global = true, help = "Output as human-readable plain text")]
    pub plain: bool,
}
```

Using `#[group(multiple = false)]` ensures clap rejects `--json --plain` at parse time with a clear error.

#### Command Enum

```rust
#[derive(Subcommand)]
pub enum Command {
    /// Connect to or launch a Chrome instance
    Connect,
    /// Tab management (list, create, close, activate)
    Tabs,
    /// URL navigation and history
    Navigate,
    /// Page inspection (screenshot, text, accessibility-tree, find)
    Page,
    /// DOM inspection and manipulation
    Dom,
    /// JavaScript execution in page context
    Js,
    /// Console message reading and monitoring
    Console,
    /// Network request monitoring and interception
    Network,
    /// Mouse, keyboard, and scroll interactions
    Interact,
    /// Form input and submission
    Form,
    /// Device and network emulation
    Emulate,
    /// Performance tracing and metrics
    Perf,
}
```

Each variant has a doc comment that becomes the short help text, plus a `long_about` for detailed AI-friendly descriptions.

### `src/error.rs` — Error Types and Exit Codes

```rust
#[repr(u8)]
pub enum ExitCode {
    Success = 0,
    GeneralError = 1,
    ConnectionError = 2,
    TargetError = 3,
    TimeoutError = 4,
    ProtocolError = 5,
}

pub struct AppError {
    pub message: String,
    pub code: ExitCode,
}
```

The `AppError` type serializes to JSON for stderr output: `{"error": "message", "code": N}`.

### `src/main.rs` — Entry Point

```rust
fn main() {
    let cli = Cli::parse();

    if let Err(e) = run(cli) {
        e.print_json_stderr();
        std::process::exit(e.code as i32);
    }
}

fn run(cli: Cli) -> Result<(), AppError> {
    match cli.command {
        Command::Connect => Err(AppError::not_implemented("connect")),
        Command::Tabs => Err(AppError::not_implemented("tabs")),
        // ... all 13 stubs
    }
}
```

No async runtime is needed for this issue — all stubs are synchronous.

---

## File Layout

| File | Purpose | Type |
|------|---------|------|
| `src/main.rs` | Entry point, dispatch | Modify |
| `src/cli/mod.rs` | Cli, GlobalOpts, OutputFormat, Command | Create |
| `src/error.rs` | ExitCode, AppError, JSON error output | Create |
| `Cargo.toml` | Add clap, serde, serde_json dependencies | Modify |

---

## Dependency Changes

### New Dependencies (in `[dependencies]`)

| Crate | Version | Features | Purpose |
|-------|---------|----------|---------|
| `clap` | 4 | `derive`, `env` | CLI argument parsing |
| `serde` | 1 | `derive` | JSON serialization |
| `serde_json` | 1 || JSON error output |

Note: `serde` is already in `[dev-dependencies]` with `derive`. Moving it to `[dependencies]` (keeping it also in dev-deps is fine — Cargo deduplicates).

---

## API / Interface Changes

### New Endpoints / Methods

| Endpoint / Method | Type | Auth | Purpose |
|-------------------|------|------|---------|
| [path or signature] | [GET/POST/etc or method] | [Yes/No] | [description] |

### Request / Response Schemas

#### [Endpoint or Method Name]

**Input:**
```json
{
  "field1": "string",
  "field2": 123
}
```

**Output (success):**
```json
{
  "id": "string",
  "field1": "string",
  "createdAt": "ISO8601"
}
```

**Errors:**

| Code / Type | Condition |
|-------------|-----------|
| [error code] | [when this happens] |

---

## Database / Storage Changes

### Schema Changes

| Table / Collection | Column / Field | Type | Nullable | Default | Change |
|--------------------|----------------|------|----------|---------|--------|
| [name] | [name] | [type] | Yes/No | [value] | Add/Modify/Remove |

### Migration Plan

```
-- Describe the migration approach
-- Reference tech.md for migration conventions
```

### Data Migration

[If existing data needs transformation, describe the approach]

---

## State Management

Reference `structure.md` and `tech.md` for the project's state management patterns.

### New State Shape

```
// Pseudocode — use project's actual language/framework
FeatureState {
  isLoading: boolean
  items: List<Item>
  error: string | null
  selected: Item | null
}
```

### State Transitions

```
Initial → Loading → Success (with data)
                  → Error (with message)

User action → Optimistic update → Confirm / Rollback
```

---

## UI Components

### New Components

| Component | Location | Purpose |
|-----------|----------|---------|
| [name] | [path per structure.md] | [description] |

### Component Hierarchy

```
FeatureScreen
├── Header
├── Content
│   ├── LoadingState
│   ├── ErrorState
│   ├── EmptyState
│   └── DataView
│       ├── ListItem × N
│       └── DetailView
└── Actions
```

---

## Alternatives Considered

| Option | Description | Pros | Cons | Decision |
|--------|-------------|------|------|----------|
| **A: Single file** | All CLI structs in main.rs | Simple, no modules | Gets unwieldy fast, doesn't follow structure.md | Rejected |
| **B: cli/ module** | Separate CLI module per structure.md | Clean separation, follows planned structure, easy to extend | One extra module | **Selected** |
| **C: cli/commands/ submodules** | One file per command group | Maximum modularity | Over-engineering for stubs; better when commands have real logic | Deferred to future issues |
| **D: clap builder API** | Use clap's programmatic builder | More control over help formatting | More verbose, harder to maintain, less idiomatic | Rejected |
| **E: Separate output module** | Full output layer now | Consistent with structure.md | Over-scoping; only error output needed now | Deferred |

---

## Security Considerations

- [x] **Input Validation**: clap handles type validation for --port (u16), --timeout (u64)
- [x] **No secrets**: No sensitive data handled in CLI parsing
- [x] **No network**: Stubs don't make any connections
- [x] **No file I/O**: Stubs don't read/write files

---

## Performance Considerations

- [x] **Startup time**: clap derive adds minimal overhead (< 1ms parsing)
- [x] **Binary size**: clap with derive adds ~1-2MB; well within 10MB target
- [x] **No async**: No runtime overhead — synchronous stubs

---

## Testing Strategy

| Layer | Type | Coverage |
|-------|------|----------|
| CLI parsing | Unit tests (in cli/mod.rs) | Verify argument parsing, defaults, conflicts |
| Error output | Unit tests (in error.rs) | Verify JSON serialization, exit codes |
| Integration | BDD (cucumber-rs) | End-to-end CLI invocation tests |
| Feature | BDD (Gherkin) | All 13 acceptance criteria as scenarios |

BDD tests will invoke the compiled binary via `std::process::Command` and assert on stdout, stderr, and exit codes.

---

## Risks & Mitigations

| Risk | Likelihood | Impact | Mitigation |
|------|------------|--------|------------|
| clap 4 API changes | Low | Low | Pin to `4` major version |
| Help text formatting varies by terminal width | Low | Low | Set `term_width = 100` in clap settings |
| Output format flag defaults need future adjustment | Medium | Low | OutputFormat struct is easy to modify; --json default can be handled in run() logic |

---

## Open Questions

- [ ] [Technical question]
- [ ] [Architecture question]
- [ ] [Integration question]

---

## Change History

| Issue | Date | Summary |
|-------|------|---------|
| #3 | 2026-02-10 | Initial feature spec |

## Validation Checklist

- [x] Architecture follows existing project patterns (per `structure.md`)
- [x] All interface changes documented
- [x] No database/storage changes (N/A)
- [x] No state management needed (N/A — synchronous CLI)
- [x] No UI components (CLI tool)
- [x] Security considerations addressed
- [x] Performance impact analyzed
- [x] Testing strategy defined
- [x] Alternatives were considered and documented
- [x] Risks identified with mitigations