greentic-start-dev 1.1.27190108346

Greentic lifecycle runner for start/restart/stop orchestration
Documentation
# Coding Agent Guide

This document is the operational source of truth for coding agents and maintainers working in `greentic-start`.

If you only want a gentle human introduction, read the [README](../README.md) first.

## What This Repo Owns

`greentic-start` owns local lifecycle execution for Greentic bundles.

In practice, that means:

- starting a bundle
- stopping a running bundle
- restarting selected services
- loading runtime config from the bundle
- launching local helper services
- exposing local ingress
- optionally exposing the admin API

It also contains app-flow execution glue around `greentic_runner_desktop::run_pack_with_options(...)`.

For broader ownership boundaries, see [ownership.md](ownership.md).

## The Commands

The `clap` surface is defined in [src/cli_args.rs](/projects/ai/greentic-ng/greentic-start/src/cli_args.rs:8).

Available commands:

- `greentic-start start`
- `greentic-start up`
- `greentic-start stop`
- `greentic-start restart`

Important behavior:

- `up` is an alias for `start`
- if no explicit subcommand is provided, argument normalization inserts `start`
- legacy `demo` prefix is stripped during argument normalization

That behavior lives in [src/cli_args.rs](/projects/ai/greentic-ng/greentic-start/src/cli_args.rs:201) and is wired in [src/lib.rs](/projects/ai/greentic-ng/greentic-start/src/lib.rs:79).

## How `start` Is Used

The usual entrypoint is:

```bash
greentic-start start --bundle /path/to/bundle
```

The runtime path is:

1. parse CLI args
2. normalize legacy/default command forms
3. resolve bundle/config paths
4. initialize logging
5. load runtime demo config
6. apply CLI overrides
7. apply tunnel behavior
8. start services and ingress

The main orchestration lives in [src/lib.rs](/projects/ai/greentic-ng/greentic-start/src/lib.rs:113) and [src/runtime.rs](/projects/ai/greentic-ng/greentic-start/src/runtime.rs:742).

## `start` Options

These are the supported `start` and `restart` flags from [src/cli_args.rs](/projects/ai/greentic-ng/greentic-start/src/cli_args.rs:24).

### Bundle and targeting

- `--bundle <path>`
  Points at the bundle root to run.
- `--config <path>`
  Uses an explicit runtime config path instead of bundle auto-resolution.
- `--tenant <name>`
  Overrides the tenant.
- `--team <name>`
  Overrides the team.

Bundle/config resolution is handled through [src/bundle_config.rs](/projects/ai/greentic-ng/greentic-start/src/bundle_config.rs:20).

### NATS

- `--nats off`
  Do not use NATS.
- `--nats on`
  Enable NATS and spawn the bundled/local runtime-managed instance.
- `--nats external`
  Use NATS without spawning it locally.
- `--nats-url <url>`
  Overrides the NATS URL.
- `--no-nats`
  Hidden legacy flag that conflicts with `--nats`.

The override behavior is implemented in [src/lib.rs](/projects/ai/greentic-ng/greentic-start/src/lib.rs:388).

Practical meaning:

- `off` disables NATS features
- `on` means `greentic-start` may spawn NATS
- `external` means the runtime expects an already-running NATS server

### Tunnels

- `--cloudflared on|off`
  Enables or disables Cloudflare Tunnel.
- `--cloudflared-binary <path>`
  Uses a specific `cloudflared` binary.
- `--ngrok on|off`
  Enables or disables ngrok.
- `--ngrok-binary <path>`
  Uses a specific `ngrok` binary.

Important automatic behavior from [src/lib.rs](/projects/ai/greentic-ng/greentic-start/src/lib.rs:194):

- if tunnel flags were not explicitly set, `.greentic/tunnel.json` may influence tunnel mode
- if no deployer packs are detected, local dev mode may auto-enable `cloudflared`
- if still not explicit, the runtime may prompt for tunnel selection in interactive use
- if `--ngrok on` and `--cloudflared on` are both present, `ngrok` wins unless you intentionally override the combination

### Runner selection

- `--runner-binary <path>`
  Uses a specific runner binary when external runner integration paths need it.

Note:

- app-flow execution in this repo also uses embedded desktop-runner execution via [src/runner_exec.rs]/projects/ai/greentic-ng/greentic-start/src/runner_exec.rs:28
- do not assume `--runner-binary` changes every execution path

### Restart targeting

- `--restart all`
- `--restart cloudflared`
- `--restart ngrok`
- `--restart nats`
- `--restart gateway`
- `--restart egress`
- `--restart subscriptions`

These values are defined in [src/cli_args.rs](/projects/ai/greentic-ng/greentic-start/src/cli_args.rs:120).

Behavior:

- `restart` with no explicit targets becomes `all`
- targeted restarts affect service restart handling during startup/orchestration

That defaulting is applied in [src/lib.rs](/projects/ai/greentic-ng/greentic-start/src/lib.rs:85).

### Logging and terminal output

- `--log-dir <dir>`
  Writes logs to a specific directory.
- `--verbose`
  Sets higher terminal log detail.
- `--quiet`
  Reduces terminal noise.

Logging initialization happens in [src/lib.rs](/projects/ai/greentic-ng/greentic-start/src/lib.rs:137).

### Admin API

- `--admin`
  Enables the mTLS admin API endpoint.
- `--admin-port <port>`
  Sets the admin port. Default is `8443`.
- `--admin-certs-dir <dir>`
  Points at the cert directory containing `server.crt`, `server.key`, and `ca.crt`.
- `--admin-allowed-clients <cn1,cn2,...>`
  Restricts allowed client certificate common names.

The admin server is started from [src/lib.rs](/projects/ai/greentic-ng/greentic-start/src/lib.rs:337) and implemented in [src/admin_server.rs](/projects/ai/greentic-ng/greentic-start/src/admin_server.rs:77).

## WebChat WebSocket Notifier

The WebChat DirectLine WebSocket endpoint (`/v3/directline/conversations/{id}/stream`)
delivers activities to connected clients through a notifier. Two backends are
supported, selected via the optional `webchat.notifier` section in
`greentic.yaml`:

```yaml
webchat:
  notifier:
    backend: redis    # "memory" (default) | "redis"
    url: redis://localhost:6379          # optional override; defaults to state-redis URL
    channel: greentic:webchat:notify     # optional override
    capacity: 64                         # optional; see note below
```

**Memory** — process-local broadcast. No external dependency. Suitable for
single-replica deployments and local development. This is the default when
the `webchat` section is absent.

**Redis** — pub/sub backplane that fans activities out across operator
replicas. URL is auto-detected from the `state-redis` provider's
`ConfigEnvelope` (run `gtc setup --provider state-redis` first to configure
the shared Redis URL). An explicit `url` field overrides auto-detect.

Field notes:

- `url` — Redis connection string. Examples: `redis://localhost:6379` (no auth),
  `rediss://user:pass@host:6380/0` (TLS + auth + database 0). Defaults to the
  `state-redis` provider's configured URL if not specified.
- `channel` — Redis pub/sub channel name. Defaults to `greentic:webchat:notify`.
- `capacity` — Number of buffered events per subscriber. Older events are dropped
  on overflow. Defaults to 64. Lower values reduce memory under high load; higher
  values allow brief Redis outages to recover without dropping messages.

Failure modes:

- Redis configured but unreachable at boot → `gtc start` exits with a clear error.
- Redis disconnects after boot → same-replica sessions keep working; cross-replica
  fan-out resumes on reconnect (exponential backoff up to 5 seconds).
- `state-redis` not configured + `backend: redis` selected → boot error pointing
  at the `gtc setup --provider state-redis` command.

## `stop` Options

The `stop` command supports the flags defined in [src/cli_args.rs](/projects/ai/greentic-ng/greentic-start/src/cli_args.rs:64).

- `--bundle <path>`
- `--state-dir <path>`
- `--tenant <name>`
- `--team <name>`

The stop request entrypoint is [src/lib.rs](/projects/ai/greentic-ng/greentic-start/src/lib.rs:93).

Use `stop` when you want to shut down an already-running runtime cleanly.

## Automatic Behaviors Agents Must Remember

### Command normalization

- `greentic-start --bundle /tmp/x` behaves like `greentic-start start --bundle /tmp/x`
- `greentic-start demo start ...` still works because the legacy `demo` prefix is stripped

### GREENTIC environment defaults

At startup, [src/lib.rs](/projects/ai/greentic-ng/greentic-start/src/lib.rs:115) ensures:

- `GREENTIC_PROVIDER_CORE_ONLY=0`
- `GREENTIC_ENV=dev` if it is not already set

Do not accidentally break these unless the contract is intentionally changing.

### DirectLine session-token renewal

The HTTP ingress fronts the webchat provider's `/v3/directline/...` endpoints and
keeps an in-memory sliding window of active conversations: on every accepted
`POST /v3/directline/conversations/<id>/activities` it extends the conversation's
lifetime, re-mints a fresh, correctly-signed bearer (same `conv`/`ctx`), swaps it
into the upstream `Authorization` header, and returns it to the client as
`_directline.renewed_token` — so a long-running chat never hits the 30-minute
`401 invalid token: Expired`. Idle conversations still lapse after the TTL.
`POST /v3/directline/tokens/refresh` is served locally (the WASM provider 404s
it) and returns a full-fresh-TTL token with the same `conversationId`. Auth
failures on these endpoints carry a machine-readable `code`
(`TokenExpired` / `InvalidToken` / `WrongConversation`) plus a `Link` header to
`/tokens/refresh` on the `401`s.

- Base TTL: `GREENTIC_DIRECTLINE_TOKEN_TTL_SECS` (seconds, clamped `[60, 604800]`,
  default `1800`). The activity-driven renewal is the actual fix; this env var is
  only the base-lifetime knob.
- Implementation: [src/http_ingress/directline_session.rs]/projects/ai/greentic-ng/greentic-start/src/http_ingress/directline_session.rs
  and the `directline_session_preflight` / `apply_directline_forward_plan` hooks
  in [src/http_ingress/mod.rs]/projects/ai/greentic-ng/greentic-start/src/http_ingress/mod.rs.
  Background: [docs/directline-token-renewal.md]/projects/ai/greentic-ng/greentic-start/docs/directline-token-renewal.md.
- WebSocket `/stream` keepalive (re-mint the pump's internal token, `touch` the
  window while connected) is not wired yet — follow-up.

### Setup-derived tunnel behavior

App startup currently consumes setup-derived tunnel configuration from `.greentic/tunnel.json`, but that does not mean all setup answers are automatically merged into app-flow runtime config.

### Provider setup versus app runtime

Provider setup has a dedicated persisted-config envelope flow:

- write config envelope in [src/provider_config_envelope.rs]/projects/ai/greentic-ng/greentic-start/src/provider_config_envelope.rs:59
- read and reapply that config in [src/providers.rs]/projects/ai/greentic-ng/greentic-start/src/providers.rs:131

App-flow execution is different:

- [src/messaging_app.rs]/projects/ai/greentic-ng/greentic-start/src/messaging_app.rs:205 forwards `input`, `tenant`, `team`, and `correlation_id`
- [src/event_router.rs]/projects/ai/greentic-ng/greentic-start/src/event_router.rs:30 forwards event payloads directly
- [src/runner_exec.rs]/projects/ai/greentic-ng/greentic-start/src/runner_exec.rs:100 passes the payload through as `RunOptions.input`

If you are debugging “why did my app node not receive setup config,” do not assume `greentic-start` automatically merges app setup values into `component.exec`.

## App Flow Execution Notes

The embedded app-flow runner path is in [src/runner_exec.rs](/projects/ai/greentic-ng/greentic-start/src/runner_exec.rs:28).

Current important details:

- flow input is written to the run directory as `input.json`
- `flow.log` is initialized under the bundle log directory
- secrets manager injection is passed into `RunOptions.secrets_manager`
- execution runs through `greentic_runner_desktop::run_pack_with_options(...)`

This is the first file to inspect when live bundle execution differs from direct runner behavior.

## Logs and State

Expect runtime data under the bundle:

- `logs/`
- `state/`
- `.greentic/`

Useful logs:

- `logs/operator.log`
- `logs/flow.log`

Useful run artifacts:

- `state/runs/.../input.json`
- `state/runs/.../run.json`
- `state/runs/.../summary.txt`

## Recommended Validation Commands

For this repo:

```bash
cargo check
cargo test
cargo build
```

For one test:

```bash
cargo test -p greentic-start test_name_here
```

For a fuller local pass:

```bash
bash ci/local_check.sh
```

## Documentation Rule For Future Changes

If you change:

- command flags
- startup defaults
- tunnel selection behavior
- restart semantics
- admin API behavior
- app-flow execution wiring

update this document and the human-facing [README](../README.md) together.