Metadata-Version: 2.4
Name: ghostlogic-agent-watchdog
Version: 0.4.0
Summary: Forensic forwarder for AI-agent coding sessions (Claude Code, Codex CLI). Tick-batches transcripts and ships tamper-evident receipts to GhostLogic Blackbox.
Project-URL: Homepage, https://github.com/adam-scott-thomas/ghostlogic-agent-watchdog
Project-URL: Repository, https://github.com/adam-scott-thomas/ghostlogic-agent-watchdog
Project-URL: Issues, https://github.com/adam-scott-thomas/ghostlogic-agent-watchdog/issues
Project-URL: Changelog, https://github.com/adam-scott-thomas/ghostlogic-agent-watchdog/releases
Project-URL: Bug Tracker, https://github.com/adam-scott-thomas/ghostlogic-agent-watchdog/issues
Author-email: Adam Thomas <adamthomasdirect@gmail.com>
Maintainer-email: Adam Thomas <adamthomasdirect@gmail.com>
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: ai-agents,audit,claude-code,codex-cli,evidence,forensics,logging,telemetry
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Environment :: No Input/Output (Daemon)
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: System :: Logging
Classifier: Topic :: System :: Monitoring
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: aiohttp>=3.9
Requires-Dist: ghostseal<2.0,>=1.0
Requires-Dist: ghostspine>=0.3.0
Requires-Dist: keyring>=24
Requires-Dist: watchdog>=4.0
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Requires-Dist: twine>=5.0; extra == 'dev'
Provides-Extra: windows
Requires-Dist: pywin32>=306; extra == 'windows'
Description-Content-Type: text/markdown

# GhostLogic Agent Watchdog

GhostLogic Agent Watchdog is the product surface for the `logicd` collection daemon. It monitors local AI-agent coding sessions, including Codex CLI and Claude Code, seals them in rolling 10-minute ticks, and ships tamper-evident work receipts to GhostLogic Blackbox over HTTPS.

`logicd` remains the internal package, module, CLI, and service-runtime name. User-facing docs and plugin metadata should refer to GhostLogic Agent Watchdog.

Repository: `ghostlogic-agent-watchdog`. Plugin manifest name: `ghostlogic-agent-watchdog`. The daemon command remains `logicd`.

## Scope

- **Sources:** Claude Code (`~/.claude/projects/**/*.jsonl`), Codex CLI (`~/.codex/sessions/**/*.jsonl`, `~/.codex/history.jsonl`).
- **Capture model:** tick-based. 10-minute ticks. Every event carries its `tick_index`; the server-side aggregator applies a 7-day rolling window as retention policy. The client does not enforce retention.
- **Transport:** `POST https://api.ghostlogic.tech/api/v1/ingest` with `Authorization: Bearer <key>`.
- **Runtime:** foreground Python process or a persistent platform launcher. On Windows, the installer registers a logon-triggered scheduled task named `logicd` that runs **as the enrolling user** (so it can read that user's keyring and `~/.claude` + `~/.codex` sessions — see F-WD-022). macOS/Linux register a per-user launchd LaunchAgent / systemd `--user` unit. Read-only on source files. ACL-locked config.
- **Platforms:** Windows, macOS, Linux (all three).
- **Forensic posture:**
  - SHA-256 on every source line.
  - Deterministic `batch_id` (`sha256` of sorted event_ids) for idempotent retries and server dedupe.
  - Append-only hash-chained audit log (`audit.log`) of every forwarder activity.
  - Byte offsets advance only after a batch has been durably handled (shipped or dead-lettered). Process death before durability means the next run re-reads those bytes, so no data loss is expected.
  - Dead-lettered batches replay on startup with the original `batch_id` preserved.
  - Every event carries `line_number`, `byte_offset`, `byte_end`, `sha256`, source adapter, and `captured_at_ns` for pinpointable forensic mapping.

## Privacy — what is transmitted

> **Private mode: transcript content is NOT transmitted. File paths, session IDs, hostname, OS username, per-line SHA-256 fingerprints, event subtype, and tool names ARE transmitted.**

`include_payload = false` (the default, "private" mode) keeps the *content* of each transcript line on your machine. It does **not** mean nothing leaves the machine: the identity and topology fields above ship unconditionally so the server can prove an event existed without seeing its content. The transport is HTTPS-only — the daemon refuses to start against a non-`https://` endpoint unless `allow_insecure_url = true` is set for local dev/staging (F-WD-019).

Set `include_payload = true` to ship full transcript bodies (still scanned by the redaction patterns in `[privacy]`).

*(Event subtype and tool-name extraction land in P2a; named here so the disclosure does not lag the code.)*

## Windows Self-Serve Install

Run PowerShell as Administrator:

```powershell
python -m pip install --upgrade ghostlogic-agent-watchdog
logicd enroll --token gl_enroll_xxx --endpoint-name $env:COMPUTERNAME --agent-id logicd
logicd install
```

`logicd enroll` redeems the one-time `gl_enroll_...` token with `https://api.ghostlogic.tech/api/v1/enroll`, writes the scoped `gl_agent_*` key locally, and does not print the full key. `logicd install` uses the enrolled config and does not prompt for a raw API key.

## Installer

For a one-command, fail-closed install/upgrade use the productized installer
(`logicd-installer`, which drives the bundled `install.ps1`). It runs the same
path for every host — including ours.

```powershell
# Elevated PowerShell:
pip install --upgrade ghostlogic-agent-watchdog
logicd-installer install --token gle_xxxxx
```

What it enforces (no flag combination can produce an unsafe state):

- **Single canonical launcher** — scheduled task `\logicd`, run as the enrolling user (logon trigger; F-WD-022). One name, ever.
- **Dual-launcher detection (fail-closed)** — if any other task references the daemon, or more than one task does, the install **refuses**. Migrate an existing host with a stray task (e.g. a hand-rolled `\GitWitness`) by running once with `--force-remove-existing` (removal is audit-logged). See F-WD-021.
- **Elevation required** — non-admin exits `NOT_ELEVATED`.
- **HTTPS + UUID + keyring** — `api.url` must be `https://`; `endpoint_id` must be the server-issued UUID (never the hostname); the key lives only in the OS keyring. Any violation rolls back.
- **Idempotent** — re-running upgrades the package, preserves `endpoint_id` + key, verifies the task in place, and bounces the service. Never creates a second task.
- **Pre-install checks + 30s post-install health** with rollback on any failure.

### Flags

| Flag | Effect |
|---|---|
| `--token gle_...` | Enrollment token (required for fresh install / `--reenroll`). |
| `--force-remove-existing` | Remove non-canonical launchers (F-WD-021 migration), then install. |
| `--dry-run` | Run pre-install checks, print intended actions, change nothing. |
| `--reenroll` | Force re-enrollment even if a healthy install exists. |
| `--data-dir <path>` | Override the platform data directory. |
| `logicd-installer uninstall` | Remove task + config + pause sentinel. **Preserves** the keyring entry and `audit.log` (forensic record). |

### Installer error codes

Every failure exits non-zero with a named code:

| Code | Meaning |
|---|---|
| `NOT_ELEVATED` (10) | Re-launch from an elevated PowerShell. |
| `PYTHON_TOO_OLD` (11) | Python 3.11+ required. |
| `API_UNREACHABLE` (12) | `https://api.ghostlogic.tech/health` did not return 200. |
| `DUAL_LAUNCHER_DETECTED` (13) | A non-canonical/extra launcher exists; re-run with `--force-remove-existing`. |
| `TOKEN_FORMAT_INVALID` (14) | Token must look like `gle_...`. |
| `WHEEL_INSTALL_FAILED` (20) | `pip install` failed. |
| `IMPORT_VERIFY_FAILED` (21) | `import logicd` failed post-install. |
| `ENROLL_HTTP_ERROR` (30) | Enrollment HTTP request failed. |
| `ENROLL_RETURNED_HTTP_URL` (31) | Server returned a non-HTTPS `api.url` (rolled back). |
| `ENROLL_RETURNED_NON_UUID` (32) | Server/config `endpoint_id` is not a UUID (rolled back, F-WD-020). |
| `KEYRING_MIGRATE_FAILED` (33) | Could not move the key out of the TOML into the keyring. |
| `TASK_CREATE_FAILED` (40) | Scheduled-task create/start/remove failed. |
| `POST_INSTALL_HEALTH_FAILED` (50) | Health check failed 30s after start (rolled back). |
| `UNINSTALL_FAILED` (60) | Uninstall step failed. |

The daemon-side `allow_insecure_url` (F-WD-019) is a **daemon** dev escape hatch, not an installer knob — the installer never accepts `http://`.

### Default locations

| Platform | Config + state directory | ACL method | Service instructions |
|---|---|---|---|
| Windows | `%PROGRAMDATA%\GhostLogic\` | `icacls` - SYSTEM + Administrators | Scheduled Task `logicd` |
| macOS | `~/Library/Application Support/GhostLogic/` | `chmod 600` - owner only | launchd LaunchAgent (per-user) |
| Linux | `$XDG_CONFIG_HOME/ghostlogic/` or `~/.config/ghostlogic/` | `chmod 600` - owner only | systemd --user unit (or system unit for root install) |

Override the default with `--data-dir`:

```bash
logicd enroll --token gl_enroll_xxx --data-dir /opt/ghostlogic
logicd install --data-dir /opt/ghostlogic
```

Legacy/manual mode is still available for operators who already have a scoped `gl_agent_*` key:

```bash
logicd install --legacy-api-key
```

## Run (foreground)

```bash
python -m logicd run --config /path/to/config.toml
```

Paths work the same on all three OSes; use your platform's path form.

## Naming Split

- Product and plugin display name: `GhostLogic Agent Watchdog`
- Repository: `ghostlogic-agent-watchdog`
- Package and plugin manifest name: `ghostlogic-agent-watchdog`
- Internal Python package and CLI module: `logicd`
- Internal config, unit, and label identifiers may still use `logicd` where stability matters

## License

Apache-2.0
