Metadata-Version: 2.4
Name: t4l-agent
Version: 0.3.2
Summary: Complete T4L Trainer agent package with embedded server and in-app chat loop.
Project-URL: Homepage, https://github.com/BigSlikTobi/t4l-agent
Project-URL: Repository, https://github.com/BigSlikTobi/t4l-agent
Project-URL: Issues, https://github.com/BigSlikTobi/t4l-agent/issues
Author: T4L Trainer
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Requires-Python: >=3.11
Requires-Dist: t4l-server<0.9.0,>=0.8.1
Provides-Extra: dev
Requires-Dist: build>=1.3; extra == 'dev'
Requires-Dist: mypy>=1.18; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.14; extra == 'dev'
Requires-Dist: twine>=6.2; extra == 'dev'
Description-Content-Type: text/markdown

# T4L Agent

`t4l-agent` runs one T4L connector and one coach loop against an existing OpenClaw agent.

OpenClaw owns the model, provider, reasoning mode, credentials, tools, and native session execution. T4L keeps those choices unchanged.

## The whole runtime

```text
T4L Trainer phone
        |
        | signed HTTPS
        v
OpenClaw t4l-connect plugin
        |
        | narrow loopback proxy
        v
t4l-agent run
  ├─ t4l-server + SQLite
  └─ coach loop -> existing OpenClaw agent
```

There are two production commands:

- `t4l-agent install` prepares an existing supported OpenClaw VPS.
- `t4l-agent run` runs the connector after setup.

## Easy VPS setup

The normal user does not need to assemble Python or npm commands. Their trusted
host agent reads the T4L install runbook and runs the pinned bootstrap:

```bash
curl -fsSL --proto '=https' --tlsv1.2 \
  https://raw.githubusercontent.com/BigSlikTobi/t4l-agent/v0.3.2/install.sh \
  | sudo bash -s -- \
      --public-url https://coach.example.com \
      --connector-owner-id webchat:gateway:operator-admin
```

The host agent supplies the real public URL and the exact verified
`channel:account:sender` identity. It also passes `--openclaw-executable` when
OpenClaw is installed outside the administrator's normal `PATH`. The script:

1. creates one private Python environment under `/opt/t4l`;
2. installs exactly `t4l-agent 0.3.2` and `t4l-server 0.8.1` from PyPI;
3. checks the existing OpenClaw agent without sending a channel message;
4. installs and pins the `t4l-connect 0.4.0` plugin through OpenClaw;
5. creates the shared host-only token and loopback systemd service;
6. checks the local connector and the restricted public HTTPS route.

This release supports Linux, Python 3.11+, and either a system-level or
current-user systemd OpenClaw Gateway owned by the administrator running the
installer. It stops safely when it cannot identify one exact Gateway service.
It never opens ports `18789` or `8787`.

If the local service is ready but the existing reverse proxy still needs its
narrow T4L route, the installer reports `LOCAL_READY`. That is not full success.
The host agent finishes the proxy work and reruns the acceptance check.

## What setup creates

The host setup does this once:

1. Install the `@t4l-trainer/openclaw-t4l-connect` plugin in the existing OpenClaw profile.
2. Configure its `agentId` and loopback `connectorBaseUrl`, normally `http://127.0.0.1:8787`.
3. Give both the OpenClaw Gateway and `t4l-agent` the same random `T4L_CONNECTOR_RUNTIME_TOKEN`.
4. Start `t4l-agent run`.

The plugin contains only:

- the authenticated pre-model `/t4l connect CODE` command;
- a strict allowlist of phone routes;
- an HTTPS-to-loopback proxy.

The plugin itself does not install packages, choose releases, manage services,
or receive provider credentials. The separate host installer owns that work.

For local plugin development:

```bash
cd openclaw_plugins/t4l-connect
npm test
npm pack --dry-run
```

Install a published version with OpenClaw's normal pinned-plugin flow. Configure it through the OpenClaw control surface for the selected profile.

## Install the Python runtime

Python 3.11 or newer is required. Install `t4l-server` and `t4l-agent` into the same environment.

For local development:

```bash
python3 -m venv .venv
.venv/bin/pip install -e ../t4l-server
.venv/bin/pip install -e '.[dev]'
```

## Run

```bash
export T4L_CONNECTOR_RUNTIME_TOKEN='replace-with-a-long-random-secret'

t4l-agent run \
  --agent-id main \
  --agent-name Atlas \
  --agent-profile coach-01 \
  --connector-owner-id 'slack:workspace-id:user-id' \
  --data-dir /srv/t4l/coach-01 \
  --host 127.0.0.1 \
  --port 8787
```

The owner identity is exactly `channel:account:sender`. Repeat `--connector-owner-id` for multiple authenticated owner channels.

Use the existing OpenClaw profile and agent id. Optional `--agent-home-dir`, `--agent-state-dir`, and `--agent-config-path` flags point at that runtime. T4L never creates a second agent.

The connector binds to loopback by default. The phone enters the public HTTPS OpenClaw Gateway address, not the loopback connector address. Public binding requires `--allow-public-bind` and still requires trusted HTTPS.

`T4L_SERVER_API_KEY` may provide a stable host-only MCP key. Otherwise the process creates one. The phone never receives it.

## Phone connection

1. The phone enters the Gateway address.
2. It creates an Ed25519 key and receives an eight-character pairing code.
3. It shows `/t4l connect XXXX-XXXX`.
4. The user sends that command in an authenticated OpenClaw owner channel.
5. The plugin forwards only the code and verified owner identity to the loopback connector.
6. The phone proves key possession and receives a device-bound token scoped to `chat`, `sync`, and `status`.

There is no post-pair installer, release selection, rollback job, second code, API-key form, or model-driven host setup.

## Coach behavior

The coach loop uses the existing OpenClaw agent with no provider, model, reasoning, or delivery override. Every turn uses a fresh isolated session key. It does not send a message through OpenClaw channels; the reviewed reply returns through T4L chat.

Purpose-specific instructions are embedded in the Python package:

- `core.md`
- `onboarding.md`
- `chat.md`
- `training-block.md`

The loop loads only the files needed for the current turn.

The phone remains authoritative:

- onboarding produces a pending `athlete_setup_draft.v1`;
- planning produces a pending `training_block_plan.v1`;
- the phone explicitly reviews and accepts both;
- the phone chooses the daily workout variant locally;
- agent chat cannot silently rewrite accepted state.

Exercise videos must be exact YouTube Shorts for the selected exercise. The host verifies the URL and live title before storing a plan.

The coach is training-and-recovery only. Nutrition, hydration, supplement, weight, and body-composition prescriptions are blocked before and after model execution.

## Development

```bash
.venv/bin/ruff format --check .
.venv/bin/ruff check .
.venv/bin/mypy
.venv/bin/pytest -q

cd openclaw_plugins/t4l-connect
npm test
npm pack --dry-run
```

The tests use runtime fakes. Before production, also run one live OpenClaw smoke test for:

- runtime readiness;
- non-delivering coach execution;
- owner and non-owner pairing commands;
- the Gateway HTTPS proxy;
- a complete phone pairing and training-block review round trip.
