Config Reference

Config Reference

All tunable parameters live in class Config in arb_bot/config.py.

Runtime-Editable Config

A subset of the knobs listed below — everything registered in arb_bot/settings/registry.py — can be changed at runtime without a code deploy or bot restart. The database stores only overrides; an absent row means "use the code default." Changes take effect immediately via Postgres LISTEN/NOTIFY (the listener thread in the running bot process receives the notification and clears the in-memory snapshot instantly). For processes that did not receive the notification, the snapshot is refreshed automatically on a 5-minute TTL. There is no outage window.

There are three ways to edit a runtime-editable knob:

  • Dashboard Settings page — navigate to /settings in the React dashboard. Knobs are grouped (Risk, Timing, DC, DCS, MDC, AI, Dry-Run). Each row shows the key, current effective value, code default, and description. Click a row to set a new value; the page validates bounds before saving.
  • Telegram /set KEY VALUE — e.g., /set DC_PROFIT_TARGET_PCT 0.38. The bot validates the type and bounds, writes to DB, and broadcasts the change.
  • Telegram /config [group] — lists all runtime-editable knobs with their current effective value. Pass a group name (e.g., /config DC) to filter the output.
Secrets and static infrastructure are never runtime-editable. Only the named scalar knobs in arb_bot/settings/registry.py go through the settings store. Everything else — API tokens, DB URLs, strategy-slot dicts, enum constants — passes through the normal class attribute path with no DB access.
Broker credentials (Phase A1) — not knobs. Live broker secrets (Dhan client_id, access_token, pin, totp_secret, token expiry) are not Config knobs and are never runtime-editable. They live Fernet-encrypted in the brokers.broker_connections Postgres table, separate from both the bot_settings runtime knobs above and the static .env infrastructure secrets. They are seeded once via scripts/seed_broker_connection.py and rotated by the token refresher. See Brokers.
Go-live state overrides dry-run flags after first run DC_DRY_RUN, DCS_DRY_RUN, SDCS_DRY_RUN, DDC_DRY_RUN, IC_DRY_RUN, MDC_DRY_RUN, and AI_MARKET_DRY_RUN are first-run or strategy-local safety defaults. Once go-live records exist, runtime state is changed with Telegram commands, not by rereading config flags. AI_MARKET remains dry-run-only in phase 1.

Capital & Risk

ParameterDefaultMeaning
PHASE1_CAPITAL₹8,00,000Capital allocated to this bot
DEPLOYED_CAPITAL₹17,00,000Operator-deployed capital used by the autonomous roadmap risk envelope.
KILL_SWITCH_LOSS−₹10,000Daily loss limit before halting new trades. Also the envelope daily cap.
WEEKLY_DD_CAP−₹25,000Risk envelope rolling weekly drawdown cap.
MONTHLY_DD_CAP−₹50,000Risk envelope absolute monthly drawdown cap.
LIFETIME_DD_CAP−₹1,00,000Risk envelope hard cumulative drawdown halt.
LOSS_STREAK_PAUSE_DAYS3Consecutive losing days that pause new entries until operator resume.
LOT_LOCK_DAYS30Minimum live-trading age before strategies can use their default lot sizing.
LOT_UNLOCK_PROFIT₹50,000Cumulative profit required, in addition to LOT_LOCK_DAYS, to unlock default lot sizing.
CASH_BUFFER_PCT15%Minimum undeployed cash fraction
MAX_OPEN_POSITIONS10Max simultaneous positions
MAX_DAILY_TRADES10Max orders per day (including reversals)
PORTFOLIO_GREEKS_GATE_ENABLEDTrueMaster switch for the portfolio Greeks runtime gate before option entries.
PORTFOLIO_BLOCK_DRY_RUNFalseWhen false, dry-run trades that would breach Greek limits still simulate so research data is preserved; SHADOW/LIVE entries are blocked.
PORTFOLIO_MAX_ABS_DELTA130.0Maximum absolute portfolio delta after adding a candidate trade.
PORTFOLIO_MAX_ABS_GAMMA0.35Maximum absolute portfolio gamma after adding a candidate trade.
PORTFOLIO_MAX_ABS_THETA25,000Maximum absolute portfolio theta per day after adding a candidate trade.
PORTFOLIO_MAX_ABS_VEGA25,000Maximum absolute portfolio vega per 1% IV move after adding a candidate trade.
BROKER_HEALTH_ENABLEDTrueMaster switch for scan-cycle broker health sampling and runtime entry downgrades.
BROKER_HEALTH_OPTION_CHAIN_LATENCY_MS2,500 msOption-chain latency threshold that degrades broker health and forces dry-run-only entries.
BROKER_HEALTH_API_LATENCY_MS1,500 msOrder, position, and margin API latency threshold that degrades broker health.
BROKER_HEALTH_RECENT_LIMIT20Recent persisted health samples returned by /api/broker/health.
IV_SNAPSHOT_RETENTION_DAYS180Prune cutoff, in days, for the iv_snapshots table. Enforced on every insert.
BATTLE_LOG_RETENTION_DAYS60Prune cutoff, in days, for the strategy_battle_log table. Enforced on every insert.

Event Calendar Guard

Parameter / CommandDefaultMeaning
EVENT_GUARD_ENABLEDTrueMaster switch for event-risk blocking before DC, DCS, DCS_SKEW, DDC, MDC, and IC scans.
EVENT_LOOKAHEAD_DAYS7Default pre-event block window for blocking market events.
EVENT_CALENDAR_SEED_FILEdata/market_events_seed.jsonManual official/seeded events loaded on bot startup and by the fetch job.
make fetch-eventsmanual/operator-runLoads the seed file, fetches NSE holidays for current/next year, fetches MoSPI CPI/GDP/IIP events, fetches OEA WPI warning events, normalizes rules, and upserts into SQLite.

Box Spread

ParameterDefaultMeaning
min_profit_per_lot (per-underlying)NIFTY ₹300 / BANKNIFTY ₹450Minimum net profit after all charges. NIFTY is lower because its premiums are structurally smaller. BANKNIFTY stays at ₹450 to absorb the ₹300–400/lot gap between scan prices and fill prices.
BOX_MAX_MARGIN_PER_TRADE₹80,000Skip if margin estimate exceeds this
BOX_CLOSE_DAYS_BEFORE_EXPIRY2Close N days before expiry (pin risk)
BOX_PROFIT_TARGET_PCT70%Close early when this % of max profit is captured

Calendar Spread

ParameterDefaultMeaning
CAL_ENTRY_SIGMA2.0Enter when spread deviates > 2σ from mean
CAL_EXIT_SIGMA0.5Exit when spread returns within 0.5σ
CAL_LOOKBACK_DAYS20Rolling window for mean / std computation
CAL_MIN_NET_PROFIT_PER_LOT₹50Skip if net profit after charges is below this
NEAR_EXPIRY_TIME_STOP_HOUR15Hour in IST for DC, DCS/DCS_SKEW, DDC, and IC expiry-day time stops.
NEAR_EXPIRY_TIME_STOP_MIN0Minute in IST for expiry-day time stops. With the default, near-expiry option spreads close at/after 15:00 IST on expiry day, or immediately if near expiry has already passed.

Double Calendar Straddle (DC)

ParameterDefaultMeaning
DC_LOT_SIZE65NIFTY lot size
DC_MIN_DTE3Minimum DTE to near expiry at entry — below this gamma risk too high
DC_MAX_DTE7Maximum DTE to near expiry at entry — beyond this theta advantage is minimal
DC_MIN_IV15%Minimum near ATM IV — enter only when premium is high enough for the theta edge to materialise
DC_MAX_IV25%Maximum near ATM IV — skip if event risk (RBI, results); IV could explode and kill the short near leg
DC_MAX_IV_SPREAD5%Skip if far_iv − near_iv > this — event premium priced into far expiry
DC_MIN_NEAR_STRADDLE80 ptsMinimum near straddle premium — enough theta to collect
DC_PROFIT_TARGET_PCT32%Close when net P&L ≥ 32% of net debit (after entry + close costs). Theta is front-loaded — bulk arrives in first 2-3 days.
DC_STOP_PNL_PCT20%Trigger 1: close if net P&L ≤ −20% of net debit. Max-loss guardrail regardless of IV or spot.
DC_STOP_IV_DROP10.0 ptsTrigger 2: close if entry IV − current IV ≥ 10 pts. IV crush kills far legs faster than near theta helps.
DC_STOP_TENT_DTE3Trigger 3 only active when DTE ≥ this — inside 3 DTE the near gamma is too volatile to trust the tent shape.
DC_STOP_TENT_WIDTH1.30Trigger 3: close if |spot − atm| > near_straddle_entry × 1.30. Widened from 0.90 after live data showed 0.90 exits consistently exited on normal NIFTY noise before theta could accrue.
DC_STOP_CONFIRM_CYCLES2Panic stops (P&L stop + tent break) must breach this many consecutive monitor cycles before closing. 1 = fire immediately (legacy). Live data showed every stop fired on a transient intraday tick — many trades were positive at the prior snapshot — so >1 requires the breach to persist. Not applied in EXPIRY_APPROACH (gamma risk demands immediate action). Shipped at 2 (A/B: DC −₹33k → −₹6.5k).
DCS_STOP_CONFIRM_CYCLES1Same as DC_STOP_CONFIRM_CYCLES but for DCS / DCS_SKEW. Separate knob so DC can gate without dragging DCS — DCS's gating effect is marginal (its losses trend rather than mean-revert).
TRAILING_PROFIT_ARM_DEBIT_PCT0.15Arm the trailing lock once peak P&L ≥ 15% of net debit — a deterministic, reachable anchor. Replaces the old expected_profit-based arm, which live data showed was unreachable (trades peaked ≈13% of debit), leaving the trail dead and peaks given back into losses.
TRAILING_PROFIT_LOCK_PCT0.70Deprecated — superseded by TRAILING_PROFIT_ARM_DEBIT_PCT. Kept for back-compat; no longer used by the exit.
TRAILING_PROFIT_FLOOR_PCT0.85Once trailing is active, close if live P&L drops below 85% of the peak seen since the lock activated. Locks in most of the profit while allowing normal intraday breathing room.
DC_MAX_MARGIN₹1,50,000Skip if net debit × lot exceeds this (capital cap per trade)
DC_MAX_CONCURRENT1Max simultaneous DC positions, counting dry-run, shadow, and live rows.
DC_DRY_RUNTrueFirst-run seed for DC go-live state. Runtime state is stored in SQLite records.
DC_REALIZED_RANGE_MAX_PCT0.45Skip DC if today's intraday spot range > 45% of near ATM straddle — prefer DCS which has OTM wings to absorb the wider range.
DC_IV_PERCENTILE_GATE_ENABLEDTrueEnable the IV percentile quality gate after DC scanner signal generation.
DC_BLOCK_TOP_IV_PERCENTILE90Skip new DC entries when mature IV history says current ATM IV percentile is at or above this threshold.

Stretched Double Calendar (DCS)

ParameterDefaultMeaning
DCS_MIN_DTE7Minimum DTE to near expiry — OTM near legs below 5 DTE have negligible theta differential (₹5-15 premium)
DCS_MAX_DTE10Maximum DTE — wider than DC to give OTM wings time to contribute theta
DCS_IV_REGIME_LOW22.5Near IV below this → low-vol tier; apply DCS_WING_PCT_LOW_IV (tighter wings, less capital).
DCS_IV_REGIME_HIGH24.0Near IV above this → high-vol tier; apply DCS_WING_PCT_HIGH_IV (wider wings to stay within likely range).
DCS_WING_PCT_LOW_IV0.45Wing = 45% of 1SD when near IV < 22.5%. Tighter tent in low-vol conditions.
DCS_WING_PCT_MID_IV0.52Wing = 52% of 1SD when 22.5% ≤ near IV ≤ 24.0%. Standard mid-vol sizing.
DCS_WING_PCT_HIGH_IV0.60Wing = 60% of 1SD when near IV > 24.0%. Wider tent to tolerate the larger expected moves.
DCS_REALIZED_RANGE_MAX_PCT0.80Skip DCS if today's intraday spot range > 80% of near ATM straddle — market too volatile for an 8-leg structure.
DCS_SKEW_THRESHOLD2.0Min IV-pt gap between put skew and call skew to trigger asymmetric wings in DCS_SKEW. Below this, wings are symmetric.
DCS_SKEW_CE_WING_PCT0.45CE wing pct used when put skew is dominant (tighter upside tent, wider downside tent).
DCS_SKEW_PE_WING_PCT0.60PE wing pct used when put skew is dominant (wider downside tent where risk is concentrated).
DCS_PROFIT_TARGET_PCT42%Close when net P&L ≥ 42% of net debit. Higher than DC's 32% — wings take 1-2 extra days to contribute.
DCS_MAX_MARGIN₹2,50,000Capital cap for 8-leg structure (net debit × lot)
DCS_DRY_RUNTrueFirst-run seed for DCS go-live state. Stop triggers same as DC (DC_STOP_*).
DCS_MAX_CONCURRENT3Max simultaneous DCS positions, counting dry-run, shadow, and live rows. Each open position must be at a different ATM + near expiry. At most one new DCS entry is allowed per calendar day.

Skew-Aware DCS (DCS_SKEW)

SkewedDCSScanner runs as a separate strategy alongside DCS for side-by-side comparison. It uses asymmetric CE/PE wings when put or call skew exceeds the threshold; otherwise identical to DCS.

ParameterDefaultMeaning
SDCS_DRY_RUNTrueFirst-run seed for skew-aware DCS go-live state.
SDCS_MAX_CONCURRENT1Max simultaneous DCS_SKEW positions, counting dry-run, shadow, and live rows. Kept at 1 during comparison phase to minimize capital commitment.
DCS_SKEW_DISABLEDFalseRe-enabled in dry-run to evaluate performance with AI market context active. Was disabled after 0% win rate in 5 live trades; scanner returns None immediately when True.

Directional Diagonal Calendar (DDC)

DirectionalDiagonalScanner is a dry-run 2-leg strategy. It buys the far-month ATM option and sells the near-week OTM option on the same side after a strong intraday trend from the captured day open.

ParameterDefaultMeaning
DDC_DRY_RUNTrueFirst-run seed for DDC go-live state.
DDC_DISABLEDFalseRe-enabled in dry-run to evaluate performance with AI market context active. Was disabled after 0% win rate in 3 live trades; scanner returns None immediately when True.
DDC_TREND_THRESHOLD_PCT0.5%Minimum absolute intraday move from captured day open before DDC can signal.
DDC_MIN_IV20%Minimum ATM IV. Config stores 0.20; scanner normalizes it to the existing percent IV convention.
DDC_MAX_IV25%Maximum ATM IV. Above this, event risk is too high for the short near-week leg.
DDC_NEAR_DTE_MIN5Minimum DTE for the near-week short leg.
DDC_NEAR_DTE_MAX9Maximum DTE for the near-week short leg.
DDC_OTM_DISTANCE_PTS200 ptsFixed OTM distance for the short near-week leg: ATM + 200 for CE, ATM − 200 for PE.
DDC_PROFIT_TARGET_PCT30%Close when net P&L reaches 30% of entry debit.
DDC_STOP_LOSS_PCT20%Close when net P&L falls to −20% of entry debit.
DDC_MAX_MARGIN₹80,000Skip signal if entry debit × lot size exceeds this cap.
DDC_MAX_CONCURRENT1Max simultaneous DDC positions, counting dry-run, shadow, and live rows.

Iron Condor Fallback (IC)

IronCondorScanner is a dry-run fallback. It only scans when no DC, DCS, DCS_SKEW, or DDC trade is open, and it persists simulated fills instead of placing live orders.

ParameterDefaultMeaning
IC_DRY_RUNTrueFirst-run seed for IC go-live state.
IC_MIN_IV18%Minimum ATM IV. Config stores 0.18; scanner normalizes it to percent.
IC_MAX_IV26%Maximum ATM IV. Above this, event risk is too high for a short-vol range trade.
IC_DTE_MIN3Minimum DTE for near-week IC entry.
IC_DTE_MAX7Maximum DTE for near-week IC entry.
IC_OTM_DISTANCE_PTS300 ptsShort CE/PE distance from ATM: CE at ATM + 300, PE at ATM − 300.
IC_WING_WIDTH_PTS200 ptsLong hedge distance beyond each short: CE wing at ATM + 500, PE wing at ATM − 500.
IC_MIN_CREDIT_PCT20%Skip if net credit is below 20% of wing width × lot size.
IC_IV_PERCENTILE_CREDIT_ADJUST_ENABLEDTrueEnable the low-IV percentile credit adjustment when mature IV history exists.
IC_LOW_IV_PERCENTILE25Percentile at or below which IC requires extra credit because short-vol premium is relatively cheap.
IC_LOW_IV_MIN_CREDIT_MULTIPLIER1.25×Multiplier applied to IC_MIN_CREDIT_PCT × wing width × lot size on low-IV percentile days.
IC_PROFIT_TARGET_PCT50%Close when credit captured reaches 50% of entry credit.
IC_STOP_LOSS_CREDIT_X1.5×Close when current loss reaches 1.5× entry credit.
IC_MAX_RANGE_PCT60%Skip if today's realized spot range exceeds 60% of the near ATM straddle.
IC_MAX_MARGIN₹60,000Skip signal if max loss estimate exceeds this cap.
IC_MAX_CONCURRENT1Max simultaneous IC positions, counting dry-run, shadow, and live rows.

AI Market Strategy

All AI calls go through CodexRunner (arb_bot/ai/codex_runner.py) which shells to codex exec — no OpenAI API key, $0 per token. Auth uses the machine's existing free ChatGPT login (mounted at ~/.codex); no API key and no per-token budget. Three flows: Flow 1 = AI_MARKET single-leg trade (premarket + confirmation), Flow 2 = shared market_view prediction every 30 min, Flow 3 = breakout_risk exit overlay every 30 min. News and macro context use SearXNG by default (SEARXNG_URL=http://searxng:8080), with Firecrawl as fallback when SearXNG is unset.

ParameterDefaultMeaning
CODEX_MODELgpt-5.6-terraModel ID passed to codex exec -m. All three AI flows use this model.
CODEX_REQUEST_TIMEOUT_SECONDS420Subprocess timeout for a single codex exec call. Longer than a typical OpenAI request because the Codex sandbox has startup overhead.
CODEX_HOMEemptyOverride path to the codex binary. When empty, the runner searches PATH and then ~/.local/bin/codex.
CODEX_USE_FREE_CHATGPT_AUTHTrueWhen true (default), the runner strips any OPENAI_API_KEY from the subprocess environment so the free ChatGPT login under ~/.codex is used untouched. Set to false only if you are paying per-token with an explicit API key. There is no AI_*_BUDGET_* config — Codex is free.
CODEX_RETRY_ON_429_TIMEOUTTrueWhen true, a transient codex failure (HTTP 429 rate-limit or a subprocess timeout) is retried up to CODEX_MAX_RETRIES times with backoff before giving up.
CODEX_MAX_RETRIES2Number of retry attempts for a transient codex failure. Total attempts = retries + 1.
CODEX_RETRY_BACKOFF_SEC20Seconds to sleep between retry attempts. Set to 0 to retry immediately (useful in tests).
ENRICHER_RETRY_COUNT2Number of retry attempts for a single data-enricher fetch (yfinance / NSE) before it is considered failed. A failed fetch falls back to the last good cached value when available.
ENRICHER_CACHE_TTL_MIN120TTL (minutes) of the in-process enricher cache. On a transient upstream failure, a stale-but-fresh value within this window is returned instead of None so a single provider outage does not force NO_TRADE.
FIRECRAWL_API_URLhttp://localhost:3002Fallback self-hosted Firecrawl API base URL. Used by MacroSearchCollector only when SEARXNG_URL is unset.
FIRECRAWL_API_KEYlocalAPI key for the self-hosted Firecrawl instance.
FIRECRAWL_ENABLEDTrueEnables the Firecrawl fallback search backend when SEARXNG_URL is unset; macro and news collection still prefer SearXNG when configured.
SEARXNG_URLhttp://searxng:8080Primary search backend for daily macro and per-cycle news enrichment. Takes priority over Firecrawl.
AI_PREDICT_ENABLEDTrueMaster switch for Flow 2 and Flow 3 (market_view + breakout_risk). Disabling this stops the 30-min scheduled runs; AI hints and breakout overlay are inactive.
AI_PREDICT_INTERVAL_MIN30How often (minutes) the market_view and breakout_risk tasks are run during market hours.
AI_PREDICT_MAX_AGE_MIN35Maximum age (minutes) of a prediction row before it is considered stale and ignored by the scan cycle.
AI_PREDICT_DAILY_RUN_CAP20Maximum prediction rows per calendar day across both tasks combined. Guards against runaway calls.
AI_HINT_ENABLEDTrueWhen true, market_view predictions are applied to strategy signals via each spec’s ai_hint_consumer. Set to false to run AI predictions but ignore the hints (shadow mode for tuning).
AI_EXIT_OVERLAY_ENABLEDTrueMaster switch for the breakout-risk exit overlay (Flow 3). Disabling skips the advisory check during position monitoring.
AI_EXIT_MIN_CONFIDENCE75Minimum breakout confidence (%) required before the overlay triggers. Below this threshold no action is taken.
AI_EXIT_AUTO_CLOSETrueWhen true, a high-confidence breakout signal auto-closes the range-bound trade and writes action_taken=AUTO_CLOSE. When false, the advisory is written as ADVISORY_ONLY and a Telegram alert is sent for manual review.
AI_EXIT_TENT_BUFFER_PCT0.5Distance from a short strike (as % of spot) within which the overlay considers the tent at risk and eligible for exit.
AI_DEBRIEF_ENABLEDTrueWhen true, closed-trade journal rows attempt a Codex-backed post-trade debrief after the close snapshot is saved.
AI_DEBRIEF_DAILY_TOKEN_BUDGET200,000Daily rolling Codex token cap across all post-trade debriefs.
AI_DEBRIEF_DAILY_COUNT_CAP50Maximum number of debriefs generated per calendar day.
AI_MARKET_ENABLEDTrueMaster switch for the scheduled 09:05 AI_MARKET analysis (Flow 1).
AI_MARKET_DRY_RUNTrueSafety default. Dry-run only — refuses live AI_MARKET broker orders.
AI_MARKET_SHADOWFalseWhen true, analysis is stored but execution is suppressed for observation-only comparison.
AI_MARKET_MAX_MARGIN₹1,00,000Maximum planned exposure for the simulated AI_MARKET trade.
AI_MARKET_LOTS1Lots used for simulated AI_MARKET trade sizing.
AI_MARKET_MIN_CONFIDENCE65Minimum confidence required before the confirmation stage can create a simulated trade.
AI_MARKET_CONFIRMATION_TIME09:20Scheduler time for the live confirmation pass.
AI_MARKET_MIN_CONFIRM_MOVE_PCT0.15Minimum confirmation move from the day’s first IV-snapshot spot before the setup is considered live enough to trade.
AI_MARKET_MAX_CHASE_MOVE_PCT0.60Maximum move before the setup is too extended to chase.
AI_MARKET_STOP_PCT0.35Index-based stop percentage for the confirmed dry-run option trade.
AI_MARKET_TARGET_PCT0.70Index-based target percentage for the confirmed dry-run option trade.
AI_MARKET_TRANSIENT_RETRIES1Retry count for transient Codex failures.
AI_MARKET_MAX_OUTPUT_TOKENS16000Codex output budget for the market analysis prompt.
AI_GATE_ENABLEDFalseOptional gate for blocking MDC entries from the AI verdict.

RegimeTA Strategy

REGIMETA is a dry-run directional single-leg strategy fed by the shared TA snapshot. Directional AI verdicts still require TA alignment. When AI is non-directional, the dry-run-only fallback can trade from strong TRENDING TA so we collect samples while AI stays conservative.

ParameterDefaultMeaning
REGIME_TA_ENABLEDTrueMaster switch for REGIMETA scan-cycle entries.
REGIME_TA_DRY_RUNTrueREGIMETA is dry-run only; live orders are not implemented.
REGIME_TA_MIN_STRENGTH50Minimum TA strength when AI is directional and aligned.
REGIME_TA_ALLOW_NON_DIRECTIONAL_AI_DRY_RUNTrueAllow dry-run REGIMETA entries from TA when AI says SIDEWAYS, NO_TRADE, or NEUTRAL.
REGIME_TA_TA_FALLBACK_MIN_STRENGTH70Minimum TA strength for the non-directional-AI dry-run fallback.

AI Market Sentiment (deterministic)

Flow 4 — a fully deterministic ~10-min intraday sentiment score (no LLM, no Codex call). SentimentService collects spot/PCR/IV + cached technicals, computes a weighted composite in [−100, +100] that renormalizes over whichever components are present, persists each reading to ai_market_sentiment, and feeds a conservative 4-condition exit overlay for range trades.

ParameterDefaultMeaning
AI_SENTIMENT_ENABLEDTrueMaster switch for the scheduled sentiment service. When false, no ai_market_sentiment rows are written and no sentiment job is scheduled.
AI_SENTIMENT_INTERVAL_MIN10Minutes between sentiment runs. Runtime-editable knob.
AI_SENTIMENT_ENRICHER_CACHE_TTL_MIN30Reserved cache TTL for enricher reuse across sentiment cycles.
AI_SENTIMENT_MIN_COVERAGE_PCT30Minimum coverage below which a sentiment reading is considered low-confidence for downstream consumers.
AI_SENTIMENT_EXIT_ENABLEDTrueMaster switch for the sentiment-risk exit overlay checked during position monitoring.
AI_SENTIMENT_EXIT_MIN_STRENGTH70Minimum strength_pct required before the overlay can trigger an exit.
AI_SENTIMENT_EXIT_MIN_COVERAGE_PCT40Minimum coverage_pct required before the overlay can trigger an exit.
AI_SENTIMENT_EXIT_ADVERSE_MOVE_PCT0.6Confirmed adverse spot move (as % from prev_close) required to confirm the flip is hurting the trade.
AI_SENTIMENT_EXIT_AUTO_CLOSETrueWhen true, a qualifying signal auto-closes the range trade and writes action_taken=AUTO_CLOSE. When false, an ADVISORY_ONLY row plus a Telegram alert is emitted.
AI_SENTIMENT_EXIT_SHADOWFalseForces advisory-only regardless of AI_SENTIMENT_EXIT_AUTO_CLOSE, for observation before trusting the overlay.
AI_SENTIMENT_W_MOMENTUM / _W_PCR / _W_VOL / _W_TECHNICAL / _W_GLOBAL0.35 / 0.25 / 0.15 / 0.15 / 0.10Component weights. Their sum need not be 1.0 — the composite renormalizes over whichever components are present, so a missing input is excluded rather than averaged as zero.

Dashboard AI Assistant

Read-only advisory widget for grounded Q&A on open/closed trades, strategies, and live market state. Answers are grounded in build_context_pack(); suggestions go to Telegram for confirmation.

ParameterDefaultMeaning
AI_ASSISTANT_ENABLEDTrueMaster switch for the dashboard floating AI assistant widget (Ask + Refresh).
AI_ASSISTANT_DAILY_CALL_CAP50Maximum cumulative assistant API calls per calendar day (both Ask and Refresh combined).
AI_ASSISTANT_SESSION_CALL_CAP20Maximum assistant API calls per user session (4-hour TTL cookie). Limits concurrent tab spam.

IV Surface Tracker

ParameterDefaultMeaning
IV_SNAPSHOT_RETENTION_DAYS180Retention window for iv_snapshots; stale rows are pruned on insert.
BATTLE_LOG_RETENTION_DAYS60Retention window for strategy_battle_log.
IV_SURFACE_SMILE_RANGE_PCT2.0Capture smile rows where strike distance from ATM is within this percent of spot.
IV_SURFACE_MAX_SMILE_STRIKES21Maximum smile rows stored per snapshot, centered on ATM.

Master DC (MDC)

MasterDCScanner is a meta-strategy wrapper. It classifies the current regime each cycle, delegates to the best DC-family sub-scanner, and stores the resulting trade under an MDC_* strategy key so it can coexist with standalone trades.

ParameterDefaultMeaning
MDC_DRY_RUNTrueFirst-run seed for MDC go-live state. MDC state is propagated into the selected sub-executor.
MDC_MAX_CONCURRENT2Max simultaneous MDC_* positions, counting dry-run, shadow, and live rows. The second real-order position still requires all controlled scale-in gates.
MDC_MAX_MARGIN₹2,50,000Per-trade margin cap applied to whichever sub-strategy is selected.
MDC_SCALE_IN_COOLDOWN_MINUTES90Minimum elapsed time from the newest remaining MDC anchor before another MDC position is considered.
MDC_SCALE_IN_MIN_MOVE_PTS200Absolute minimum NIFTY movement required from the anchor spot.
MDC_SCALE_IN_STRADDLE_PCT0.50Dynamic movement threshold as a fraction of the anchor near straddle; effective threshold is the maximum of this value and the fixed-point minimum.
MDC_SCALE_IN_MAX_ANCHOR_LOSS_PCT0.10Scale-in is blocked when anchor P&L is at or below −10% of its strategy risk basis.
MDC_TREND_THRESHOLD_PCT0.006Intraday spot move ≥ 0.6% from the captured open → trending → DDC.
MDC_SKEW_THRESHOLD2.5CE/PE IV gap in points → skewed → DCS_SKEW.
MDC_CALM_RANGE_PCT0.35Realized range / near straddle ≤ 35% → calm → DC.
MDC_WIDE_RANGE_PCT0.7035% to 70% → wider → DCS; above 70% → IC fallback or no trade.
MDC_MAX_IV_FOR_DC25.0Near IV above this makes DC unattractive; the wrapper falls through to IC.
MDC_MAX_IV_FOR_IC30.0Near IV above this is too risky even for IC, so the wrapper returns no signal.
MAX_CONCURRENT_OPEN_TRADES2Phase 2: Hard cap on live/shadow open trades across all strategies. Per-strategy *_MAX_CONCURRENT limits separately count dry-run, shadow, and live rows so deployed dry-run validation cannot churn unlimited open positions. The global cap still prevents correlated real exposure explosion during high-IV days.
STRATEGY_SLOTS{"dc_family": 2}Explicit DC-family exposure cap. The second slot is available only after MDC cooldown, movement, anchor-health, margin, Greeks, and exact-leg duplicate gates; a third entry is blocked.

Order Execution

ParameterDefaultMeaning
ORDER_SLIPPAGE_PCT0.2%Drift buffer added on top of the scanner bid/ask anchor (first attempt). Previously 0.4% LTP-based — that approach consistently underpriced BUY legs since LTP + 0.4% often sat below the ask on wide BANKNIFTY spreads.
LEG_RETRY_SLIPPAGE_PCT0.8%Retry uses fresh LTP + 0.8% (not bid/ask anchor) — on retry, the scanner price is too stale to trust so we fall back to aggressive LTP-based crossing.
REVERSAL_LIMIT_SLIPPAGE_PCT0.1%When reversal IS needed, _auto_reverse() tries IOC LIMIT at LTP ± this much first, then MARKET as fallback. Captures roughly half the bid-ask spread vs a direct MARKET hit (~₹150-200 saved per forced reversal).
ORDER_FILL_TIMEOUT30 sMax wait for all legs to fill (internal)
NSE_TICK_SIZE₹0.05All limit prices rounded to this boundary
ORDER_DELAY_SEC0.3 sDelay between consecutive order placements
OPTION_CHAIN_COOLDOWN3.5 sMin gap between option chain API calls

Partial Fill Recovery

ParameterDefaultMeaning
RECOVERY_TRAILING_STOP_PCT3%Trailing stop from peak LTP on kept leg
RECOVERY_TAKE_PROFIT_PCT10%Take profit from entry LTP on kept leg
RECOVERY_DIRECTION_LOOKBACK10Compare current spot vs this many readings ago (Gate 1)
RECOVERY_MIN_TREND_PCT0.15%Minimum point-to-point move to pass Gate 1; below this → FLAT
RECOVERY_CONSISTENCY_THRESHOLD60%Minimum fraction of tick intervals that must move in the trend direction to pass Gate 2. Filters spikes that fool Gate 1.

Market Index Dashboard

Live NSE index tiles (LTP + day change% + sparkline) pushed over /ws/live on a decoupled timer. MarketIndexService batches LTP via the shared DhanClient and caches per-index intraday candles. The enabled-index list is persisted as JSON in the Postgres bot_settings table and edited via GET/PUT /api/market/indices/config.

ParameterDefaultMeaning
MARKET_INDEX_REFRESH_SEC60Seconds between /ws/live index frames. Runtime-tunable (10–600 s); drives the decoupled index push timer independent of trade-monitoring ticks.
MARKET_INDEX_INTRADAY_INTERVAL5Dhan intraday candle interval (minutes) used for the sparkline series.
MARKET_INDEX_INTRADAY_CACHE_SEC240Server-side intraday cache TTL — roughly one fetch per 5-min candle to respect DhanHQ rate limits.
MARKET_INDEX_SPARKLINE_POINTS75Number of recent points rendered in each index tile's sparkline.
MARKET_INDEX_DEFAULTS7 indicesDefault NSE indices (Dhan marketfeed segment IDX_I): NIFTY_50 (13), NIFTY_BANK (25), NIFTY_NEXT50 (38), NIFTY_MIDCAP100 (37), NIFTY_SMLCAP100 (5), NIFTY_500 (19), INDIA_VIX (21). Each tuple is (key, label, segment, security_id).

Research Strategies

Equity research subsystem configuration. Read-only backtest engine; never touches live trading. See arb_bot/research/ and docs/research_backtest.md.

ParameterDefaultMeaning
RESEARCH_FUNDAMENTALS_ENABLEDTrueEnable fundamentals injection into market_data each rebalance (ROE, D/E, margin, FCF derived from yfinance).
RESEARCH_FUNDAMENTALS_FILING_LAG_DAYS45Days after period_end before fundamental data is available (avoids lookahead bias on point-in-time snapshots).
RESEARCH_MQ_MIN_ROE0.12momentum_quality: minimum ROE quality gate (12% threshold for financial health).
RESEARCH_MQ_MAX_DE1.0momentum_quality: maximum debt-to-equity ratio (leverage cap).
RESEARCH_MQ_QUALITY_WEIGHT0.5momentum_quality: blend weight for quality z-score vs momentum z-score (0.5 = equal).
RESEARCH_QA_MIN_ROE0.15quality_alpha: minimum return on equity (15% threshold).
RESEARCH_QA_MIN_ROCE0.15quality_alpha: minimum return on capital employed; approx. = ROE via yfinance derivation.
RESEARCH_QA_MAX_DE0.6quality_alpha: maximum debt-to-equity (stricter than momentum_quality for high-quality screen).
RESEARCH_QA_MIN_MARGIN0.08quality_alpha: minimum net profit margin (8% operational efficiency threshold).
RESEARCH_QA_TREND_FILTERTruequality_alpha: enable 200-SMA price trend filter (confirm uptrend before entry).
RESEARCH_QA_TREND_SMA200quality_alpha: SMA period (days) for trend filter.
RESEARCH_VT_MIN_PASS2value_trend: minimum value metrics ≥ universe median to qualify (E/P, B/P, S/P, div yield); requires ≥2 of 4.
RESEARCH_VT_TREND_SMA200value_trend: SMA period (days) for trend confirmation filter.
pair_statarb strategy (market-neutral pairs trading)
RESEARCH_PAIR_LOOKBACK120pair_statarb: lookback window (days) for spread z-score calculation.
RESEARCH_PAIR_CORR_MIN0.8pair_statarb: minimum closing-return correlation to qualify as a cointegrated pair (same sector).
RESEARCH_PAIR_Z_IN2.0pair_statarb: entry z-score threshold (|z| ≥ this triggers long/short placement).
RESEARCH_PAIR_Z_OUT0.5pair_statarb: exit z-score threshold (mean reversion exit when |z| ≤ this).
RESEARCH_PAIR_Z_STOP3.5pair_statarb: extreme-loss exit when |z| ≥ this (cointegration break protection).
RESEARCH_PAIR_MAX_PAIRS10pair_statarb: maximum concurrent pairs to trade (capital split equally per pair).
RESEARCH_PAIR_MAX_HOLDING_DAYS30pair_statarb: maximum holding period (days) — force-exit after this regardless of z-score.
RESEARCH_SHORT_BORROW_BPS_ANNUAL50pair_statarb: annualized short-borrow cost (basis points); accrued daily on short-leg notional.
options_vol_premium strategy (IV-rank iron condor)
RESEARCH_OVP_MIN_IVRANK0.5Minimum IV-rank to open an OVP iron condor (0–1)
RESEARCH_OVP_IVRANK_LOOKBACK120Rolling window (days) for IV-rank calculation
RESEARCH_OVP_DELTA0.16Approximate delta target for short strikes (informational)
RESEARCH_OVP_DTE_MIN5Minimum DTE to open a new OVP position
RESEARCH_OVP_DTE_MAX10Maximum DTE to open a new OVP position
RESEARCH_OVP_WING_POINTS300Points from spot to short strike; wings bought same distance further out
RESEARCH_OVP_PROFIT_TARGET0.5Close at this fraction of max credit received (0.5 = 50%)
RESEARCH_OVP_STOP_MULT2.0Close when loss exceeds this multiple of credit received
RESEARCH_OVP_LOT_SIZE50Contract lot size for NIFTY (units per trade)
RESEARCH_COMBINE_MODEoffCombination mode: off | composite (Mode A z-blend) | sleeve (Mode B)
RESEARCH_COMBINE_MEMBERSComma-separated member strategy names for combination runs
RESEARCH_COMBINE_WEIGHTSComma-separated weights aligned to RESEARCH_COMBINE_MEMBERS
RESEARCH_EVENTS_ENABLEDTrueInject corporate-events dict into market_data on each rebalance
RESEARCH_EVENT_LOOKBACK_DAYS5Rolling window (calendar days) for which events are visible to strategies
RESEARCH_PEAD_MIN_SURPRISE0.05Minimum earnings surprise (fraction, e.g. 0.05 = 5 %) to trigger PEAD entry
RESEARCH_PEAD_HOLDING_DAYS40Maximum holding period for earnings_pead positions (calendar days)
RESEARCH_EVENT_TYPES_ENABLEDbuyback,index_inclusion,pledge_reduction,block_deal,earningsComma-separated event types the event_driven strategy will act on
RESEARCH_EVENT_HOLDING_DAYS30Maximum holding period for event_driven positions (calendar days)

Backtest Config Overrides

The backtesting engine does not add live config parameters — instead it temporarily overrides existing Config attributes per simulated cycle through a BacktestConfig proxy (arb_bot/backtest/simulation/context.py).

  • Validation up front. BacktestConfig({...}) raises ValueError for any key that is not a real Config attribute, so a typo in a CLI/API parameter fails before simulation starts. It always forces OPTION_CHAIN_COOLDOWN = 0 so replays do not sleep between option-chain fetches.
  • Disabled-strategy replay. Standalone DDC/DCS_SKEW runs, and MDC runs that may select them, temporarily set DDC_DISABLED = False and/or DCS_SKEW_DISABLED = False inside the isolated backtest worker unless the caller explicitly supplies those keys. Live process values remain unchanged.
  • Temporary, cycle-local patching. Existing scanners and exit helpers read Config class attributes directly. Rather than refactor them, the engine wraps each historical cycle in patch.object(Config, key, value) for every validated override and restores the original class attributes when the cycle exits.
  • Restoration guarantee. After every cycle the live Config values are exactly what they were before — a unit test asserts a patched value is reverted on context exit.
  • Worker-process isolation. Single runs and grid-search combinations execute in separate ProcessPoolExecutor worker processes. Because patch.object mutates class attributes, process isolation prevents one job's overrides from being observed by another job or by the live bot process. Workers receive the database db_path (a string), never a live source or SQLite connection.

Default grid-search sweeps live in arb_bot/backtest/optimizer/param_space.py and reference only real Config keys:

StrategySwept Config keys
DCDC_STOP_TENT_WIDTH, DC_PROFIT_TARGET_PCT, DC_STOP_PNL_PCT
DCS / DCS_SKEWDCS_STOP_TENT_WIDTH, DCS_PROFIT_TARGET_PCT
DDCDDC_STOP_LOSS_PCT, DDC_PROFIT_TARGET_PCT
ICIC_PROFIT_TARGET_PCT, IC_STOP_LOSS_CREDIT_X
MDCMDC_TREND_THRESHOLD_PCT, MDC_CALM_RANGE_PCT, MDC_WIDE_RANGE_PCT

Backtest fill model

Two Config attributes exist solely for the backtest fill model — they have no effect on live trading:

ParameterDefaultMeaning
BACKTEST_SPREAD_PCT1.2%Backtest fill model: full bid-ask spread as a fraction of premium. Every simulated fill pays half of it — buys fill higher, sells fill lower. Matches the Black-Scholes synthesizer's spread model.
BACKTEST_SPREAD_MIN₹0.50Minimum full spread per leg in the backtest fill model. Set both spread params to 0 to reproduce pre-fill-model results.

Portfolio Sync Reliability

Throttle and backoff knobs for the automatic portfolio broker-sync loop run by the token-refresher container. See Portfolio Connections & Sync Reliability for the full auto-refresh model.

ParameterDefaultMeaning
PORTFOLIO_INTRADAY_SYNC_INTERVAL_MIN30 Minimum minutes between automatic intraday portfolio syncs for DHAN / ZERODHA / MO_RISE connections (read off the dedicated last_auto_sync_at throttle timestamp, not the manual-sync updated_at).
PORTFOLIO_SYNC_MAX_FAILURES_STALLED10 Consecutive failures after which a connection enters the STALLED terminal state — auto-sync stops retrying it until a manual sync succeeds (which resets failure_count via record_success).

The escalating failure backoff schedule [1, 5, 15, 60] minutes is the BrokerSyncStateRepository._BACKOFF_MINUTES constant in arb_bot/portfolio_app/db/repository.py (capped at 60 min, reached at the 4th consecutive failure), not a Config value.

Validation Framework (Evidence Spine Phase 2)

ParameterDefaultMeaning
VALIDATION_FOLD_COUNT3Number of walk-forward folds for validation.
VALIDATION_OOS_HOLDOUT_PCT0.20Fraction of data held out for out-of-sample testing.
VALIDATION_CAL_TOLERANCE_DAYS2Max day offset for matching backtest/live trade pairs during calibration.
VALIDATION_MIN_WIN_RATE0.60Minimum required win rate to pass validation.
VALIDATION_MIN_PF1.0Minimum required profit factor to pass validation.
VALIDATION_MAX_FOLD_VARIANCE0.20Max allowed variance across walk-forward folds.
VALIDATION_CAL_MAX_MEAN_ABS_DELTANoneIf set, max allowed mean absolute P&L delta between backtest and live (None = no gate).
VALIDATION_MIN_TRADES_PER_FOLD2Minimum trades required per walk-forward fold.
VALIDATION_FRESHNESS_WINDOW_DAYS30Max age of a VALIDATED event before re-validation is required for strategy go-live.

Portfolio Benchmark (Slice 2)

Benchmark knobs for the Returns page and the evening index-close fetch job. See Portfolio Reports for the returns methodology and benchmark data source.

ParameterDefaultMeaning
PORTFOLIO_BENCHMARK_DEFAULTNIFTY_50Default benchmark index for the Returns page and the scheduler fetch job.
PORTFOLIO_BENCHMARK_FETCH_TIME_IST18:30IST time the daily benchmark-close fetch job runs (post-market close).
PORTFOLIO_BENCHMARK_INDICESNIFTY_50 → ^NSEI, SENSEX → ^BSESNLogical index name to yfinance symbol map used by the reports API and the fetcher.
PORTFOLIO_BENCHMARK_FETCH_LOOKBACK_DAYS5Number of daily closes pulled each evening by the benchmark job.

Portfolio capital-gains reporting

Defaults for the read-only FIFO tax-lot estimate. See Portfolio Tax Lots for the methodology and ledger limitations.

ParameterDefaultMeaning
CAPITAL_GAINS_LTCG_EQUITY_MONTHS12Equity holding period must be strictly longer than this many months for LTCG.
CAPITAL_GAINS_LTCG_DEBT_MONTHS36Debt/bond holding period threshold for LTCG.
LTCG_EQUITY_RATE10%Estimated equity LTCG rate after the FY exemption.
LTCG_EQUITY_EXEMPTION_INR₹1,25,000Annual equity LTCG exemption used once across the report.
STCG_EQUITY_RATE15%Estimated equity STCG rate.
LTCG_DEBT_RATE20%Estimated pre-Apr-2023 debt-MF/bond LTCG rate.
STCG_DEBT_RATE30%Configurable slab-rate estimate for debt gains that are not eligible for LTCG.

Diversification & rebalance thresholds

Concentration-warning and currency-normalization knobs for the portfolio Diversification and Rebalance reports. See Portfolio Reports for the report surface.

KnobDefaultPurpose
PORTFOLIO_CONCENTRATION_SYMBOL_THRESHOLD_PCT10.0Single-holding % above which a concentration warning fires.
PORTFOLIO_CONCENTRATION_SECTOR_THRESHOLD_PCT40.0Sector % above which a concentration warning fires.
PORTFOLIO_OVERLAP_WARNING_THRESHOLD_PCT5.0Effective portfolio % at which duplicated direct/fund/ETF stock exposure is reported.
PORTFOLIO_FUND_HOLDINGS_STALE_DAYS7Age after which a manual fund or ETF constituent snapshot is marked stale.
PORTFOLIO_USD_TO_INR_FALLBACK83.5Fallback USD→INR rate for diversification/rebalance normalization.

Sector enrichment

A daily PortfolioScheduler job backfills Holding.sector for equity holdings missing one, using yfinance .info (the same source as beta). Only listed equities are enriched; funds, bonds, commodities, and unlisted holdings have no sector and are skipped. The job runs a bounded retry loop when it encounters transient lookup failures, then repeats once per evening (plus a one-shot fetch shortly after each restart) and only touches holdings with an empty sector, so newly-synced assets are classified within a day. Dashboard-only deployments also start the same boot-time enrichment worker at API startup, so sectors do not remain stuck on the fallback `Unknown` value when the trading bot is not running. Precious-metal symbols such as `XAUUSD` and `XAGUSD` are reclassified as commodities during the same boot pass. Operators can also run `/refresh_sectors` in Telegram or use the Portfolio Settings “Refresh Sectors” button to force the same backfill on demand. See Portfolio Reports.

KnobDefaultPurpose
PORTFOLIO_SECTOR_FETCH_TIME_IST18:45IST cron time for the daily sector-enrichment job (after the benchmark fetch).
PORTFOLIO_SECTOR_FETCH_DELAY_S0.5Seconds to wait between yfinance calls (Yahoo rate-limit throttle).
PORTFOLIO_SECTOR_BOOT_DELAY_MIN2Minutes after restart to fire a one-shot sector backfill (in addition to the daily cron). 0 disables the boot fetch.

Dashboard Live Fallbacks

The dashboard primarily receives live trade ticks and Market Indices through /ws/live. When the WebSocket is reconnecting, it falls back to authenticated REST reads:GET /api/trades/live for current trades and GET /api/market/indices for the latest index snapshot.

If Dhan returns an empty index LTP response, the dashboard reloads any credentials already rotated by the token-refresher and retries once. A continued failure returns the last good values with a stalemarker and applies MARKET_INDEX_FAILURE_BACKOFF_SEC (default15 seconds) before the shared service probes Dhan again. This prevents concurrent browser reconnects from amplifying an upstream market-feed outage. The recovery path is read-only: it never generates a token or places an order.

Portfolio valuation is separate from the index widget. The bot runsPORTFOLIO_PRICE_REFRESH_INTERVAL_MIN every 10 minutes by default, updates holding prices, and persists a matchingportfolio_snapshots record for Networth and each portfolio. Portfolio Overview reads the updated holdings; Reports reads those same persisted valuations. The authenticated refresh endpoint follows the same path for an immediate manual or visible-page refresh.

Option Cockpit (M2)

KnobDefaultPurpose
Config.WS_TICK_INTERVAL (existing)15Server-side dashboard tick interval (preserved unchanged). Echoed in the v2 subscribed frame.
Config.OPTION_COCKPIT_VALUATION_TTL_SECONDS1.0TTL for the global single-flight valuation cache; must satisfy >= Config.LTP_COOLDOWN.
Config.LTP_COOLDOWN (existing)1.0Broker LTP cooldown; the valuation cache TTL must be >= this value.
CAPABILITY_TIMEOUT_MS8000Fixed pre-subscribed capability timeout; transitions to UNAVAILABLE with reason server_out_of_date.
HEARTBEAT_TIMEOUT_MSderivedmax(90000, 3 * tick_interval_seconds * 1000, 3 * heartbeat_interval_seconds * 1000).

Agent Gateway advisory-run configuration

The Agent Gateway container reads two distinct database DSNs from the runtime secret store. They are NEVER derived from a globalConfig.DATABASE_URL and the container ships without a repository .env.

VariableRolePurposeRequired privileges
AGENT_DATABASE_URLread / gatewayDurable gateway claims, agent-runs persistence, Council evidence reads, decision-observability outbox writes.SELECT on read tables; ALL onagent_gateway schema. NO INSERT /UPDATE on portfolio,brokers, options_council, ordecision_observability tables.
AGENT_ADVISORY_WRITE_DATABASE_URLadvisory writerAI Research run creation, Options Council decision persistence. May be empty when no cost-incurring capability flag is set.Separately authorized. May differ in role, host, and port from AGENT_DATABASE_URL.

Capability-aware readiness

The readiness probe (GET /health/ready) returns HTTP 503 when an enabled cost-incurring capability cannot reach its hard dependency:

  • AGENT_ENABLE_RESEARCH_RUNS=true requiresAGENT_ADVISORY_WRITE_DATABASE_URL to be configured and reachable; otherwise the probe reportsunavailable_capabilities: ["research"].
  • AGENT_ENABLE_COUNCIL_RUNS=true requires the writer DSN for Council decision persistence.
  • AGENT_ENABLE_PAPER_PROPOSALS=true requires the writer DSN for paper-proposal persistence.

Default-off capabilities do not affect readiness. The probe body never exposes the writer DSN, password, or any other secret.

Safe disable and rollback

To disable a cost-incurring capability at runtime:

  1. Set the corresponding flag to false(AGENT_ENABLE_RESEARCH_RUNS=false, etc.) and restart the gateway. The flag is read at process start; an in-place change without restart is not honored.
  2. Optional: clear AGENT_ADVISORY_WRITE_DATABASE_URL if no other capability needs it. A missing writer DSN no longer affects readiness once the flags are off.
  3. Roll back by reversing the flag and confirmingGET /health/ready returns 200 with the writer DSN reachable.

Federation destination policy

Remote agent registrations pass through a strict destination-address policy. The following address categories are always rejected — no hostname allowlist can exempt them:

  • loopback (127.0.0.0/8, ::1)
  • link-local (169.254.0.0/16, fe80::/10)
  • multicast (224.0.0.0/4, ff00::/8)
  • unspecified (0.0.0.0, ::)
  • reserved (per IANA special-purpose registry)
  • cloud metadata destinations (169.254.169.254, fd00:ec2::254)

Private (RFC1918 / ULA) addresses are permitted only when the hostname is in AGENT_REMOTE_ALLOWLIST AND the resolved address is in AGENT_INTERNAL_ADDRESSES orAGENT_INTERNAL_CIDRS. A hostname alone is never sufficient.