# Autonomous agent harness FlintTrade's existing Autonomous Agent now has an isolated **Practice** runtime. It reuses `AutonomousTrader`, configured and authorised market-data reads, Laya admission and the real `SandboxEngine`. It does not place real-money orders. ## Before starting - Use a full, authenticated Practice session. An example-data session (JWT claim `explore`, chip **Example**), a setup token, an expired session, or a contradictory mode header cannot start this runtime. - Enable `ai.autonomous_agent.enabled` in the workspace. Configure an LLM using the existing AI settings and establish the configured market-data accounts. - Laya must satisfy the normal Practice admission requirements. A configured chat model is not Laya readiness, and Practice readiness is not Live approval. - The canonical calendar, rate limiter, sandbox and backend ownership must be available. The harness does not remove native-account setup/read-port guards. - Start with an empty Practice position book and no pending Practice orders. Existing manual exposure is not silently adopted by an agent. Select **Advanced** skill level and **Practice** mode, then open **AI → Agent**. Enter exact instrument symbols, exchange, position quantity in **units**, stop-loss percentage and take-profit percentage. For derivatives, use the exact contract and its valid quantity; the harness does not guess a lot size from an underlying name. Start is an explicit operator action. An optional entry rationale (up to 2,000 characters) records your standing purpose for the entries. This is operator-authored text, not model reasoning. Laya still decides each proposal; providing a rationale does not approve a refusal or clamp. Never put credentials in this field. ## Behaviour Broker reads share a rate limiter across request threads and background loops. Single quotes, batch quotes and quote-backed depth consume the same quote budget as well as the generic data budget; Dhan's published quote/depth cap is one request per second. Other reads retain the generic data budget. Waiting calls recheck current authority before reaching the provider. Throttled reads also recheck authority at least once per second, so revoked or stale queues drain together without spending refills. Cancellation while waiting spends no token. In-place limiter rate changes preserve credit rather than opening a new burst. Dhan now provides cash-equity depth for exact NSE/BSE instruments through its existing `quote_data` transport and the authenticated `BrokerReadOwner`. The canonical instrument resolver must agree on symbol, exchange, security ID and `EQUITY` instrument class (separate from exchange subtype); a supplied security ID must match. Non-cash exchanges retain the explicit `unsupported` depth outcome before consuming quote/data quota, rather than blocking otherwise supported read-only analysis. The documented REST and SDK response envelopes are validated before copying buy/sell ladders. Missing or ambiguous instruments, malformed levels, negative/non-finite numbers and fractional counts fail closed. Explicit empty sides and zero levels remain explicit source data. No depth, quantity or derivative lot metadata is invented. This is an offline-tested in-process capability. Native HTTP reads still return `409`, account mutations still return `503`, and streaming-depth readiness remains unchanged. It does not prove a live Dhan feed or a full market-day Practice run. Transport/schema references: [Dhan Market Quote](https://dhanhq.co/docs/v2/market-quote/) and the [pinned SDK response wrapper](https://github.com/dhan-oss/DhanHQ-py/blob/v2.2.0/src/dhanhq/dhan_http.py). The worker waits outside the effective market session. During an open session it reads authorised market data, asks the configured LLM for a signal, applies agent limits and submits through canonical Practice admission. New entries also require the shared L5 kill switch to be available and clear. A kill latch brakes new model work and entries; only server-proven reducing exits remain available. Final write admission is held only around the synchronous sandbox write, after Laya has decided. Laya refusals and quantity clamps do not place an order and are never automatically accepted or retried. Orders require a confirmed sandbox fill before they become tracked agent positions. Percentage-based stop and target monitoring thresholds are rebased on that confirmed fill, preserving the assessed percentages rather than retaining stale quote-based levels. Derivative orders require an exact, freshly receipted contract lot size from the authorised quote account. Missing metadata or a quantity that is not a valid lot multiple is refused; there is no lot-size fallback. A daily-loss brake stops new entries while retaining protective monitoring. Stop and session-boundary cleanup use the existing protective-exit logic; refused or uncertain exits remain visible. A stop received during a slow model or admission call is checked again before an entry can be written. Feature disablement and market-session changes also brake new entries. The agent settles positions before a daily reset and runs the existing learning reflection after a flat session. Stored lessons may inform later prompts; they cannot alter safety limits or grant execution authority. ### Bounded model usage Every Practice run has explicit model bounds: - `model_call_limit`: 500 by default, an integer from 1 to 10,000 across the entire run, including every signal request and post-session reflection - `model_output_limit`: 512 by default, an integer from 16 to 4,096 output tokens per request These are request and output limits, **not a currency cap or an input-token limit**. Provider pricing and billed usage can vary. Failed requests and unknown outcomes still consume a reserved attempt. The limit does not reset with the trading session, and no run is silently resumed after interruption. The runtime freezes a dedicated copy of the selected model configuration when the run starts. Later Settings changes apply to future runs. Provider fallback and empty-reasoning retries are disabled for this client, and per-call output overrides cannot exceed the run's limit. A request cannot select a different model from the frozen configuration. Other AI clients are unchanged. A `model_attempt_reserved` event must commit before each provider request. If that evidence cannot be written, no request is sent. The final reserved request may complete its decision and pass normal entry admission. A later request is refused before dispatch, stops new entries and initiates normal protected settlement. Reflection is skipped once no attempts remain. Budget exhaustion is a normal stop reason, distinct from an unavailable or failing model. Analysis admission freshly checks the shared kill switch, operator session, runtime ownership, stop state and session boundaries before reservation and again immediately before provider dispatch. A safety refusal does not consume an attempt unless its reservation had already committed; it records a safe `safety_brake` reason without labelling the provider unavailable. Active kill switches also skip post-session reflection. Status snapshots expose `model_usage` with both limits, `model_calls_used`, `model_calls_remaining` and `status` (`available`, `exhausted` or `evidence_unavailable`). Reservation evidence contains only safe counts and operation/status labels, never prompts, responses, API keys or provider error text. After interruption, the latest reservation events remain the durable record of attempted usage, even if the last cycle snapshot was not committed. The run remains bound to its original signed operator session. It cannot renew authentication or reconstruct credentials from saved evidence. Session expiry, revoked backend ownership, unavailable required inputs or failed persistence stop new execution and can require reconciliation. ## Run history and recovery Practice run identity, configuration, lifecycle, snapshots and ordered events are stored in `practice_agent_runs.sqlite` in the platform workspace. Auth credentials are not stored in this ledger. Each lifecycle transition commits its run row, snapshot and transition event atomically; a failed write cannot leave a phantom successful transition. The UI exposes run history and paginated evidence, including refusals and interrupted runs. After a process interruption, an active run becomes **Reconciliation required**. It is never silently resumed and uncertain orders are never replayed. Inspect Practice positions and pending orders, then use the explicit resolution action. The backend must prove the sandbox is flat before releasing the run for a new start. Resolution is an acknowledgement of the reconciled state, not an order or an automatic liquidation. One app-owned worker and one durable active run are allowed. The runtime retains ownership until execution, learning and resource cleanup actually complete. An incomplete stop must not be presented as a successful flat shutdown. ## API Existing control endpoints select the runtime from the signed session mode: - `POST /api/v1/ai/agent/start` - `POST /api/v1/ai/agent/stop` - `GET /api/v1/ai/agent/status` Practice evidence endpoints require a full Practice session and the owning operator identity: - `GET /api/v1/ai/agent/practice/runs` - `GET /api/v1/ai/agent/practice/runs/{run_id}/events?after=0&limit=100` - `POST /api/v1/ai/agent/practice/runs/{run_id}/resolve` A current running worker is not equivalent to a ready decision provider or a qualified trading strategy. Read the lifecycle and last failure together. ## Live boundaries and evidence limits The existing Live agent retains operator-approved entry intentions and the Laya → SafetySystem → `gate_order` → `BrokerRouter` chain. A broker order-id acknowledgement is not a confirmed fill: an approved Live intention cannot rotate into another intention for that symbol without reconciliation. Automated tests use synthetic model/data boundaries, real signed test sessions and a real sandbox. Such tests prove the local wiring and failure handling; they are not a real trading-day run, native-broker live acceptance, profitable strategy qualification, distribution signing, or funded-order authorisation. The separate native account-lifecycle, forecast, research-isolation and qualification backlog remains subject to its own implementation and evidence gates.