# CLI Tool Mode

Default Webwright runs (`/webwright:run`, plain prompt) produce a one-shot
`final_script.py` that solves the task for the literal values the user
provided. **CLI tool mode** (`/webwright:craft`) instead produces a
**reusable, parameterized CLI tool**: the same script can be re-run later
with different argument values to perform the same kind of task.

This mode is adapted from `webwright/src/webwright/config/crafted_cli.yaml`'s
"Final-Script Shape (CLI Tool, MANDATORY)" contract. The OpenAI-backed
`self_reflection` gate is replaced by your own self-verification against
`plan.md`.

## When to use

Trigger CLI tool mode when:

- the user invokes `/webwright:craft …`, or
- the user says "make it reusable", "parameterize", "turn this into a CLI",
  "I want to call this again with different X", or similar.

Otherwise, stay in default one-shot mode.

## `plan.md` — add a `# Parameters` section

Before writing the script, identify every requirement the user could
plausibly vary and list them in `plan.md` **in addition to** the usual
`# Critical Points` checklist:

```markdown
# Task
<verbatim task description>

# Parameters
| name    | type | source phrase from task | default     | allowed / format        |
|---------|------|-------------------------|-------------|-------------------------|
| <arg_a> | str  | "..."                   | "<value>"   | <format / allowed set>  |
| <arg_b> | int  | "..."                   | <value>     | <range or units>        |
| <arg_c> | str  | "..."                   | "<value>"   | <format>                |

# Critical Points
- [ ] CP1: ...
- [ ] CP2: ...
```

Rules:

- Every entry in `# Parameters` must (a) become a function argument and
  (b) become an `argparse --flag` with the listed default.
- Items that are truly fixed for the site (start URL, site name, selector
  strategy) are NOT parameters — keep them hard-coded.
- Defaults reproduce the original task exactly. Running
  `python final_script.py` with no arguments must reproduce the task.
- Critical Points are still required; they are the verification contract.

## `final_script.py` — required shape

1. **One reusable function** named after the task domain. Examples:
   - `def search_<domain>(arg_a, arg_b, ...): ...`
   - `def lookup_<entity>(query, filters): ...`

2. **Google-style docstring** with summary, full `Args:` block, and
   `Returns:`. Each `Args:` entry documents:
   - the argument name and type,
   - what it represents in the task domain,
   - accepted format / units / allowed values,
   - the default (mirroring the `# Parameters` table).

   ```python
   def search_<domain>(arg_a: str, arg_b: int, arg_c: str) -> dict:
       """<One-line summary of what this tool does on the target site>.

       Args:
           arg_a: <what it represents>; <format / allowed values>.
               Default: "<value>".
           arg_b: <what it represents>; <range / units>.
               Default: <value>.
           arg_c: <what it represents>; <format>.
               Default: "<value>".

       Returns:
           dict with keys ``<key1>`` (<type>), ``<key2>`` (<type>),
       """
   ```

3. **`argparse` CLI** under `if __name__ == "__main__":`. Every function
   argument has a matching `--<arg>` flag with `type=`, `help=` (copied
   from the docstring), and `default=` equal to the concrete task value:

   ```python
   if __name__ == "__main__":
       import argparse
       parser = argparse.ArgumentParser(
           description=search_<domain>.__doc__.splitlines()[0])
       parser.add_argument("--arg-a", dest="arg_a", type=str,
                           default="<value>",
                           help="<copied from docstring>")
       parser.add_argument("--arg-b", dest="arg_b", type=int,
                           default=<value>,
                           help="<copied from docstring>")
       parser.add_argument("--arg-c", dest="arg_c", type=str,
                           default="<value>",
                           help="<copied from docstring>")
       args = parser.parse_args()
       result = asyncio.run(_run(**vars(args)))
       print(result)
   ```

4. **Side-effect-free at import time.** No browser launch, no network
   call, no file write at module top-level. The reusable function must be
   importable from another Python process without triggering a run.

5. **Action-log parameter echo.** The first line written to
   `final_script_log.txt` after reset MUST be a `step 0 params: ...`
   line listing every resolved argument as `name=value` pairs, e.g.:

   ```
   step 0 params: arg_a=<value> arg_b=<value> arg_c=<value>
   ```

   so the resolved inputs are visible in any verification pass.

6. Same instrumentation as default mode: viewport 1280×1800, headless
   local Firefox, no `full_page=True`, screenshots saved as
   `final_runs/run_<id>/screenshots/final_execution_<step>_<action>.png`,
   final datum appended to `final_script_log.txt`.

## Verification (replaces `self_reflection`)

In addition to the default self-verification (every CP in `plan.md`
ticked with cited screenshot/log evidence), CLI mode requires:

1. **Reproduce the task with no arguments.** Inside a fresh
   `final_runs/run_<id>/`:

   ```bash
   cd final_runs/run_<id> && python final_script.py
   ```

   The run must succeed end-to-end and produce the expected screenshots
   and `step 0 params: ...` log line.

2. **Import-safety smoke test.** From any other directory:

   ```bash
   python -c "import importlib.util, pathlib; \
     spec = importlib.util.spec_from_file_location('fs', 'final_runs/run_<id>/final_script.py'); \
     m = importlib.util.module_from_spec(spec); spec.loader.exec_module(m); \
     print([n for n in dir(m) if not n.startswith('_')])"
   ```

   This must complete instantly with no browser launch and print the
   reusable function's name.

3. **Optional second run with a different argument value.** Demonstrates
   parameterization actually works. Run inside `final_runs/run_<id>_alt/`
   (or just save its log/screenshot folder there). Skip only if the
   alternate value would clearly fail (e.g. an unsupported value on the
   target site).

4. **Print `--help`.** End by showing the user:

   ```bash
   python final_runs/run_<id>/final_script.py --help
   ```

## Completion gate (CLI mode)

Set the task complete only when **all** are true:

1. `plan.md` contains both `# Parameters` (with name, type, source phrase,
   default, allowed/format) and `# Critical Points` checklists.
2. `final_script.py` defines exactly one reusable function with a
   Google-style `Args:` docstring covering every parameter.
3. Every `# Parameters` entry maps 1-to-1 to a function argument **and**
   an argparse `--flag` whose default equals the concrete task value.
4. The script is import-safe (smoke test passes).
5. `python final_script.py` (no args) inside `final_runs/run_<id>/`
   reproduced the task; all CPs verified against saved screenshots and
   the action log.
6. `step 0 params: ...` line is present in `final_script_log.txt`.
7. The user has seen the final datum **and** the `--help` output so they
   know how to call the tool again with different arguments.

If any of those is false, do not declare done — diagnose, fix the script
(preserving the CLI shape), re-run inside the next `run_<id+1>/`, and
re-verify.
