# Architecture

```text
Browser
  │ HTTPS + authenticated session + CSRF
  ▼
public/api.php
  ├── Auth / rate limits / audit
  ├── ProjectService
  │     ├── PathGuard
  │     ├── GitService
  │     ├── ProposalRepository
  │     └── DiffService
  ├── Agent
  │     └── OpenAI Responses API with function tools
  └── DeploymentService (manual action only)
```

## Tool loop

1. The browser sends a user request and recent conversation messages.
2. `Agent` sends the request, project rules, and strict tool schemas to the Responses API.
3. The model may request read-only tools or proposal tools.
4. PHP validates and executes each tool locally.
5. Tool results are returned to the model using the matching `call_id`.
6. The loop continues until the model returns a final text response.
7. Proposed writes remain JSON records in `storage/proposals`.
8. A user reviews the generated diff and explicitly applies or rejects each proposal.

## Proposal types

`replace`
: Replaces one exact block that must occur exactly once. Best for small, safe edits.

`write`
: Creates a new text file or replaces a complete text file. Used when an exact replacement is not practical.

Each proposal records the original and proposed SHA-256 values. Apply fails if the current source no longer matches the proposal's original hash.

## No arbitrary shell

Git and PHP lint commands are constructed as argument arrays and executed without a shell. The production command is a fixed array from server-side configuration. User prompts cannot insert shell syntax into those commands.

## Extending the starter

Reasonable next additions include:

- multi-file transaction groups with one Apply action;
- configurable test-command allowlists;
- database migration proposal files without execution;
- Git branch/push/PR controls;
- screenshot-based staging verification;
- cPanel UAPI integration using a narrowly scoped token;
- WebAuthn or TOTP for panel login;
- per-user roles and approval history.
