name: synthetix description: Help users get started with the Synthetix perps exchange — install the SDK, connect to the API, fetch market data, and place their first trade. argument-hint: "[what you want to try, e.g. 'place a limit order' or 'stream prices']"
You are helping a user try out the Synthetix perpetual futures exchange using the synthetix-sdk Python package (published on PyPI). Walk them through setup and usage interactively.
Setup (run automatically before any code)
Before running any SDK code, always ensure the environment is ready. Do not ask — just do it:
- Check if
.venv/bin/python3exists in the project root. If yes, use it directly as the Python interpreter. - If no
.venvexists, create one and install the SDK pluspython-dotenv(a dev dependency needed for loading.envfiles):python3 -m venv .venv && .venv/bin/pip install -e . python-dotenv - Always use
.venv/bin/python3to run scripts — never barepython3which is the system Python without deps.
# One-liner: ensure venv exists and SDK is installed, then run:
[ -f .venv/bin/python3 ] || (python3 -m venv .venv && .venv/bin/pip install -e . python-dotenv)
.venv/bin/python3 -c "import synthetix; print('SDK ready')"
Core dependencies (from pyproject.toml): requests, eth-account, websockets. Python 3.10+.
Also install: python-dotenv (dev dependency, needed for .env file loading in scripts).
All examples should use from dotenv import load_dotenv; load_dotenv() to pick up URL overrides from .env. If REST_URL_OVERRIDE / WS_URL_OVERRIDE are not set, the SDK defaults to production.
What they need
- Read-only (market data, prices, orderbook): No private key needed.
- Trading (orders, positions, account management): Requires a private key set as
PRIVATE_KEYenv var.
How to help
- Ask what they want to try if
$ARGUMENTSis empty. Present these categories:- Fetch market data — markets, prices, orderbooks, recent trades (no wallet needed)
- Stream live prices — real-time WebSocket price feeds (no wallet needed)
- Stream orderbook — real-time bids/asks via WebSocket with snapshot, diff, or managed modes (no wallet needed)
- Place a trade — market, limit, stop-loss, and take-profit orders (needs private key)
- Manage orders — modify, cancel, or batch multiple orders (needs private key)
- Check positions & P&L — open positions, portfolio value, balance (needs private key)
- Funding rates & fees — current rates, historical funding, fee tiers (no wallet for rates, wallet for payment history)
- Stream account updates — real-time position and order fills via WebSocket (needs private key)
- Manage risk — set leverage, place TP/SL orders, monitor exposure (needs private key)
- Account management — create subaccounts, transfer collateral, delegate signers (needs private key)
- Trade history & fills — past orders, executed trades, P&L reconciliation (needs private key)
- Write a small standalone script tailored to what they want. Use the examples in
examples/rest/andexamples/ws/as reference for correct patterns. - Explain what the script does briefly so they learn the SDK.
- Offer a next step — e.g. "Want to try placing an order next?" or "Want to stream this via WebSocket instead?"
Key patterns to follow
- REST methods are synchronous, WebSocket methods are async (
asyncio). - Client constructor:
Synthetix(private_key=os.environ["PRIVATE_KEY"], rest_url=os.environ.get("REST_URL_OVERRIDE"))for trading,Synthetix(rest_url=os.environ.get("REST_URL_OVERRIDE"))for read-only. - Prices and quantities are human-readable decimal strings (e.g.
"0.01","2500.50"), not wei. - WebSocket subscriptions use
await snx.subscribe(channel, callback, on_error=on_error, **params)and must run inside an async function. - Always clean up WS connections with
await snx.unsubscribe(sub_id)andawait snx.close().
Available operations
Market data (no auth): get_markets(), get_market_prices(), get_orderbook(symbol), get_last_trades(symbol), get_funding_rate(symbol), get_open_interest(), get_candles(symbol, interval), get_exchange_status(), get_tiers(), get_collaterals()
Trading (auth required): market_order(symbol, side, quantity), place_order(symbol, side, quantity, ...), twap_order(symbol, side, quantity, duration_seconds, price=..., interval_seconds=0, interval_variance_bps=0, size_variance_bps=0), modify_order(order_id, ...), cancel_order(order_id), cancel_all_orders(symbol), schedule_cancel(timeout_seconds) (dead-man switch / auto-cancel)
Account (auth required): get_positions(symbol=None), get_open_orders(), get_order_history(), get_trades(), get_trades_for_position(position_id, limit=0, offset=0), get_portfolio(), get_balance_updates(), get_fee_rate(), get_rate_limits(), last_rate_limits (property — free rate-limit snapshots, see "Rate limits" below), get_withdrawable_amounts(symbols), update_leverage(symbol, leverage), create_subaccount(name), transfer_collateral(amount, to_subaccount_id, symbol), voluntary_collateral_exchange(source_asset, target_usdt_amount)
WS subscriptions: All subscribe() calls accept an optional on_error=callback to handle exceptions without losing the subscription. Examples: subscribe("marketPrices", callback, on_error=on_error, symbol=...), subscribe("orderbook", callback, on_error=on_error, symbol=..., depth=50, format="snapshot"), subscribe("trades", callback, on_error=on_error, symbol=...), subscribe("candles", callback, on_error=on_error, symbol=..., interval=...), subscribe("subAccountUpdates", callback, on_error=on_error), subscribe("liquidations", callback, on_error=on_error, symbol=...) (requires a concrete symbol; "ALL" is not supported)
WS trading (async): All REST trading methods have ws_ prefixed async equivalents — e.g. await snx.ws_market_order(...), await snx.ws_twap_order(...). Also: await snx.ws_get_exchange_status() queries both REST and WS servers in parallel. WS queries: await snx.ws_get_trades_for_position(position_id, limit=0, offset=0), await snx.ws_get_withdrawable_amounts(symbols), await snx.ws_get_fee_rate().
Market data details
When the user asks to fetch market data, these are the available endpoints (all public, no auth):
-
get_markets()— all tradeable perps. Returns list of dicts withsymbol,baseAsset,quoteAsset,minOrderSize. -
get_market_prices()— current prices for all markets. Returns dict keyed by symbol withbestBid,bestAsk,markPrice,volume24h. Compute mid price as(bestBid + bestAsk) / 2. -
get_orderbook(symbol)— REST snapshot. Returns{"bids": [[price, size], ...], "asks": [[price, size], ...]}. Bids are descending, asks ascending. -
get_last_trades(symbol, limit=50)— recent public trades. Returns list of dicts withtimestamp,side,price,quantity. -
get_open_interest()— OI for all markets. Returns list of dicts withsymbol,openInterest,longOpenInterest,shortOpenInterest,timestamp(ms, always populated), and an optionalerrorMessage. A single market's lookup can fail without failing the request (returns 200): that entry haserrorMessageset and empty open-interest fields. -
get_candles(symbol, interval, start_time=0, end_time=0, limit=0)— OHLC data. Response wraps candles: use.get("candles", []). Each candle hasopenTime,openPrice,highPrice,lowPrice,closePrice,volume. Intervals:"1m","5m","15m","30m","1h","4h","8h","12h","1d","3d","1w","1M","3M". -
get_exchange_status()— maintenance check viaGET /status, queries both REST and WS servers. Returns{"rest": {...}, "ws": {...}}, each withmaintenance(bool) andmessage(str, only present when maintenance is on). Async variant:await ws_get_exchange_status()(queries both in parallel). -
get_tiers()— exchange fee/account tier configuration. Returns a list of tier dicts, each withtierId,tierType,tierName,minTradeVolume(str),makerFeeRate/takerFeeRate(str),maxSubAccounts/maxOrdersPerMarket/maxTotalOrders(int),maxBorrowCapacity(str). Use to display fee schedules or determine which tier the user qualifies for based on volume. -
get_collaterals()— collateral asset configuration. Returns a list of dicts, each withcollateral(symbol),depositCap/lltv/ltv/market/withdrawFee(str), andtiers(list of dicts withid(int) andhaircut/maxAmount/minAmount/name/valueAddition/valueRatio(str)).
See examples/rest/fetch-markets.py, fetch-ticker.py, fetch-mids.py, fetch-orderbook.py, fetch-trades.py, fetch-open-interest.py, fetch-candles.py, fetch-exchange-status.py, fetch-tiers.py, fetch-collaterals.py.
Streaming live prices details
Subscribe to the "marketPrices" channel for real-time price updates:
sub_id = await snx.subscribe("marketPrices", callback, on_error=on_error, symbol="ETH-USDT")
- Callback receives price data objects directly.
- No auth required.
- Always clean up:
await snx.unsubscribe(sub_id)thenawait snx.close(). - Use
try/finallywithasyncio.sleep(duration)to run for a set time.
Error handling: Pass on_error=callback to subscribe() to catch exceptions in your callback without losing the subscription. Error callback signature: on_error(exc, data).
See examples/ws/async-watch-ticker.py and async-watch-ticker-on-error.py.
Also available: "trades" channel for real-time public trade feed, and "candles" channel with timeframe param (e.g. "1h").
See examples/ws/async-watch-trades.py, async-watch-candles.py.
Orderbook streaming details
When the user asks to stream the orderbook, explain the three modes and guide them toward managed mode for production use:
- Snapshot mode (
format="snapshot") — each message is the full book. Simple but more bandwidth. - Diff mode (
format="diff") — first message is a snapshot, then only changed levels. Levels withquantity: "0"are removals. - Managed mode (diff + local state + verification) — production-grade. Build a local book from diffs, validate with CRC32 checksums and sequence numbers.
Managed orderbook pattern
Each diff message includes:
meseq— message sequence numberprevMeseq— expected previous sequence number (detect gaps)checksum— CRC32-IEEE hex string to verify local book integrity
Checksum format: concatenate b{price}:{quantity}| for each bid (descending), then a{price}:{quantity}| for each ask (ascending), truncated to the subscribed depth. CRC32 the resulting string and format as 8-char lowercase hex.
On sequence gap (prevMeseq != book.meseq): resubscribe to get a fresh snapshot.
On checksum mismatch: resubscribe to get a fresh snapshot.
See examples/ws/async-watch-orderbook-managed.py for the complete reference implementation with the ManagedOrderbook class.
Orderbook subscription params
depth—10,50(default), or100updateFrequencyMs—50,100,250(default),500, or1000. Whendepth=100, only250/500/1000are allowed.format—"diff"(default) or"snapshot"
Trading details
Order types
- Market —
market_order(symbol, side, quantity)— fills immediately at best price. Simplest way to enter/exit. - Limit GTC —
place_order(symbol, side, quantity, price=..., order_type="limitGtc")— rests on the book until filled or canceled. - Limit IOC —
place_order(..., order_type="limitIoc")— fills what's available immediately, cancels remainder. No resting order. - Post-only —
place_order(..., post_only=True)— rests on the book as a maker order; rejected if it would immediately match (cross the spread). Works with bothlimitGtcandlimitGtd. - Limit GTD —
place_order(symbol, side, quantity, price=..., order_type="limitGtd", expires_at=unix_ts)— rests on the book until filled, canceled, or expiry (10 s to 24 h from now). - TWAP —
twap_order(symbol, side, quantity, duration_seconds=300, price=..., interval_seconds=0, interval_variance_bps=0, size_variance_bps=0)— time-weighted average price execution over a duration. Optionalpriceas a limit ceiling/floor; optionalinterval_secondsoverrides the server default slice interval (30 s). Optionalinterval_variance_bps/size_variance_bps(0–2000) randomize each child slice's timing and size. Constraints: minimum notional $10,000 USD (quantity × markPrice), duration 300 s (5 min) to 86,400 s (24 h). - Trigger Take-Profit —
place_order(..., order_type="triggerTp", trigger_price=..., is_trigger_market=True, reduce_only=True)— triggers market order when price reaches target. Use opposite side of position. - Trigger Stop-Loss —
place_order(..., order_type="triggerSl", trigger_price=..., is_trigger_market=True, reduce_only=True)— same as TP but triggers on adverse price.
Batch orders
place_orders(orders, grouping="na") — submit multiple orders atomically. Orders are dicts with camelCase keys: symbol, side, orderType, price, quantity, reduceOnly, closePosition, clientOrderId, triggerPrice, isTriggerMarket.
Client order IDs
Use from synthetix.signing import generate_client_order_id to create UUID-style client order IDs (cloids). Pass as client_order_id when placing, then cancel with cancel_order_by_cloid(cloid) — avoids needing to track venue-assigned order IDs.
WebSocket trading
All REST trading methods have async ws_ equivalents: ws_place_order(), ws_market_order(), ws_modify_order(), ws_modify_order_by_cloid(), ws_cancel_order(), ws_cancel_order_by_cloid(), ws_cancel_all_orders(), etc. Same params, just await them and call await snx.close() when done.
See examples/rest/create-market-order.py, create-limit-gtc-order.py, create-limit-gtd-order.py, create-limit-ioc-order.py, create-limit-post-only-order.py, create-twap-order.py, create-trigger-tp-order.py, create-trigger-sl-order.py, batch-orders-tpsl.py, batch-orders-twap.py. WS: examples/ws/async-create-order.py, async-create-limit-post-only-order.py, async-create-limit-gtd-order.py, async-create-twap-order.py, async-market-order.py.
Order management details
modify_order(order_id, price=..., quantity=..., trigger_price=...)— update price, quantity, and/or trigger price of a resting order. Order ID must be int.modify_order_by_cloid(client_order_id, price=..., quantity=..., trigger_price=...)— modify a resting order by client order ID (string) instead of venue order ID.orderIdandclientOrderIdare mutually exclusive (server rejects both). Async:await snx.ws_modify_order_by_cloid(...).cancel_order(order_id)— cancel by venue order ID (int).cancel_order_by_cloid(cloid)— cancel by client order ID (string).cancel_all_orders(symbol)— cancel all resting orders for a symbol. Symbol list must be non-empty.
See examples/rest/modify-order.py, modify-order-by-cloid.py, cancel-order.py, cancel-order-by-cloid.py, cancel-all-orders.py. WS: examples/ws/async-cancel-order.py, async-cancel-order-by-cloid.py, async-modify-order-by-cloid.py.
Dead-man switch (schedule cancel) details
Also known as: auto-cancel, deadman timer, heartbeat cancel.
schedule_cancel(timeout_seconds) arms a server-side timer. If the server does not receive another schedule_cancel call (heartbeat) within timeout_seconds, it automatically cancels all open orders on the subaccount. Pass timeout_seconds=0 to disarm.
- Arm:
snx.schedule_cancel(timeout_seconds=300)— orders auto-cancel after 5 min of silence. - Heartbeat: call
schedule_cancel(timeout_seconds=300)again periodically (before the timeout expires) to keep orders alive. - Disarm:
snx.schedule_cancel(timeout_seconds=0). - Returns
{"isActive": bool, "timeoutSeconds": int, "triggerTime": int|null, "message": str}. - WS equivalent:
await snx.ws_schedule_cancel(timeout_seconds).
Typical pattern: place orders, arm the dead-man switch, then send heartbeats in a loop. If the bot crashes, the server cancels everything.
See examples/rest/schedule-cancel.py, examples/ws/async-schedule-cancel.py.
Positions & P&L details
get_positions(symbol=None)— open positions. Passsymbol(e.g."BTC-USDT") to filter by market. Each hassymbol,side("LONG"/"SHORT"),quantity,entryPrice,unrealizedPnl,liquidationPrice(optional, use.get()).get_open_orders()— resting orders. Each hasorder({"venueId": str}),symbol,side,type,price,quantity. OptionaltwapDetailsdict present on TWAP orders:averagePrice,intervalMs,intervalVarianceBps,sizeVarianceBps,totalTrades,tradesFilled,totalFees,startedAtMs,totalDurationMs.get_order_history()— filled, cancelled, rejected orders. IncludesfilledQuantity,status. Use.get()for optional fields.get_sub_account()— current subaccount balance. Returnscollaterals[](each withsymbol,quantity,withdrawable) andcrossMarginSummarywithaccountValue,availableMargin,totalUnrealizedPnl.get_portfolio()— time-series portfolio snapshots.
Polling: For live monitoring without WebSocket, use get_positions() or get_sub_account() in a while True loop with time.sleep(5). See examples/rest/poll-positions.py, poll-balance.py.
WS queries: await snx.ws_get_positions(symbol=None), await snx.ws_get_open_orders() — same data, async.
See examples/rest/fetch-positions.py, fetch-open-orders.py, fetch-order-history.py, fetch-balance.py, fetch-portfolio.py.
Funding rates & fees details
Public (no auth):
get_funding_rate(symbol)— current funding rate for a symbol.get_funding_rate_history(symbol, start_time, end_time)— historical rates. Times in milliseconds. Useint(time.time() * 1000)for current time, subtract24 * 60 * 60 * 1000for 24h window. Response wraps data infundingRateskey.
Authenticated:
get_funding_payments()— your funding payment history. Returnssummary(aggregated) andfundingHistory[](individual payments withtimestamp,symbol,fundingRate,payment).get_fee_rate()— your current maker/taker fee rate and tier schedule. Returnsvolume14d(str),currentTier(dict:tierId,tierLevel,tierName,tierType,minTradeVolume,makerFeeRate,takerFeeRate), top-levelmakerFeeRate/takerFeeRate(str),tiers[](full fee schedule),referralDiscountApplied(bool), andreferralDiscount(str multiplier,"0"when none). Async:await snx.ws_get_fee_rate().
See examples/rest/fetch-funding-rate.py, fetch-funding-rate-history.py, fetch-funding-payments.py, fetch-fee-rate.py, examples/ws/async-fetch-fee-rate.py.
Rate limits details
get_rate_limits()— current usage:{"requestsUsed": int, "requestsCap": int}. Consumes rate-limit tokens itself — preferlast_rate_limitsfor monitoring. Async:await snx.ws_get_rate_limits().snx.last_rate_limits(property, free) — the Synthetix exchange attachesrateLimit(subaccount order bucket) andipRateLimit(per-IP bucket) snapshots to every response envelope when the corresponding limiter ran. The SDK scrapes them on every REST call and WS post, so reading the property costs nothing. Returns{"rest": {"rateLimit": {...}|None, "ipRateLimit": {...}|None}, "ws": {...}}; each snapshot is{"requestsCap": int, "remainingTokens": int}.None= no response has carried that snapshot yet; an omitted key keeps its last known value.- On a 429 reject, the raised
ClientError(fromsynthetix.rest.api) carriese.rate_limit/e.ip_rate_limit(pre-debit snapshots). A 429 is authoritative — back off even ifremainingTokensis still positive.
See examples/rest/fetch-rate-limits.py, rate-limit-headroom.py, examples/ws/async-rate-limit-headroom.py.
Streaming account updates details
Subscribe to "subAccountUpdates" for real-time position changes, order fills, and balance updates:
sub_id = await snx.subscribe("subAccountUpdates", callback, on_error=on_error)
- Requires auth (private key).
- No params needed — subscribes to the current subaccount.
- Callback receives full subaccount state updates (positions, balances, margins).
- Pass
on_error=callbackto catch exceptions without losing the subscription (see "Streaming live prices" for error callback pattern). - Use
pprint()in callback to explore the data structure.
See examples/ws/async-watch-positions.py.
Risk management details
update_leverage(symbol, leverage)— set leverage for a symbol (e.g.,update_leverage("ETH-USDT", 10)).- Take-profit/Stop-loss — place trigger orders against existing positions. See "Trading details" above for
triggerTp/triggerSlorder types. - Reduce-only — set
reduce_only=Trueon TP/SL orders to prevent accidentally reversing a position. - Monitor exposure — combine
get_positions()withget_sub_account()to see margin usage, unrealized P&L, and liquidation prices.
See examples/rest/set-leverage.py, create-trigger-tp-order.py, create-trigger-sl-order.py.
Account management details
create_subaccount(name)— create a new subaccount with a display name.get_sub_accounts()— list all subaccounts with full data (positions, collaterals, margin summary per account).transfer_collateral(amount, to_subaccount_id, symbol="USDT")— move collateral between subaccounts. Requires at least 2 subaccounts. Convert subaccount ID to int.voluntary_collateral_exchange(source_asset, target_usdt_amount)— exchange a non-USDT collateral for USDT.source_assetis the collateral symbol to convert from (cannot be"USDT");target_usdt_amountis either the literal string"all"or a positive decimal string of USDT to receive. Returns{"sourceAsset", "sourceAmountTaken", "targetAsset", "targetAmount", "indexPrice", "effectiveHaircut", "collateral": [{"symbol", "quantity"}]}. Async:await snx.ws_voluntary_collateral_exchange(source_asset, target_usdt_amount).withdraw_collateral(amount, symbol="USDT", destination=None)— withdraw to wallet. Defaults to own wallet if destination is omitted. When signing as a manager/delegated wallet (not the subaccount owner), withdrawals are only permitted to the owner's wallet address; any otherdestinationreturns a 403 Forbidden error. Returns{"requestId", "symbol", "amount", "destination", "usdtNotional"}whereamountis the gross amount reserved (includes withdrawal fee) andusdtNotionalis the spot USDT value of the net disbursement at request time. Async:await snx.ws_withdraw_collateral(amount, ...).get_withdrawable_amounts(symbols, subaccount_id=None)— withdrawable collateral per symbol (e.g.["USDT"]; at least one required). Returns{"items": [...], "totalWithdrawableUsdt": str}where each item hassymbol,quantity(total balance),withdrawableAmount(free to withdraw after margin/pending/fee),pendingWithdraw,withdrawFee. Async:await snx.ws_get_withdrawable_amounts(symbols).
Delegation:
add_delegated_signer(delegate_address, permissions)— delegate trading to another wallet. Permissions is a list (e.g.,["session"]).get_delegated_signers()— view active delegations.remove_delegated_signer(delegate_address)— revoke delegation.
See examples/rest/create-subaccount.py, transfer-collateral.py, voluntary-collateral-exchange.py, fetch-sub-accounts.py, add-delegated-signer.py, fetch-delegated-signers.py, remove-delegated-signer.py. WS: examples/ws/async-voluntary-collateral-exchange.py.
Trade history & fills details
get_balance_updates(start_time=0, end_time=0, action_filter=None, limit=0, offset=0, subaccount_id=None, transfer_types=None)— deposits, withdrawals, and transfers.action_filteris a comma-separated list ofDEPOSIT,WITHDRAWAL,TRANSFER.transfer_typesis a list of transfer-type slugs ("user","slp_takeover","collateral_exchange","admin","referral_commission") that filters TRANSFER rows.limitdefaults to 50 (max 1000);offsetdefaults to 0 (max 10000). Returns{"balanceUpdates": [...]}, each withid,action(DEPOSIT/WITHDRAWAL/TRANSFER),status(success/completed/pending),amount,grossAmount(amount + fee),fee,usdtNotional(spot USDT value at the time of the transaction),collateral,timestamp. TRANSFER entries also includefromSubAccountId/toSubAccountId; deposits/withdrawals includedestinationAddress/txHash.get_trades(order_id=None)— your executed fills. Optionally filter by venue order ID. Response wraps data: use.get("trades", []). Also includeshasMore(bool) andtotal(int) for pagination. Each trade hastimestamp,symbol,side,price,quantity,fee,realizedPnl(optional).get_trades_for_position(position_id, limit=0, offset=0)— fills for a specific position. Returns{"trades": [...], "hasMore": bool}. Each trade hastradeId,symbol,orderType,side,price,quantity,realizedPnl,fee,feeRate,timestamp,maker,reduceOnly,markPrice,entryPrice,direction,postOnly. Async:await snx.ws_get_trades_for_position(position_id).get_order_history(start_time=0, end_time=0, limit=0)— historical orders (filled, cancelled, rejected). Passstart_time/end_timein ms (max 7-day window). Each hasorder({"venueId": str}),symbol,side,type,price,filledQuantity,status. Optional fields:cancelReason,triggerPrice(str, stop/trigger price for TP/SL orders),triggerPriceType("last"or"mark"),tpOrder/slOrder(dict{"venueId": str}cross-linking the sibling in a positionTpsl pair — the TP record carriesslOrderpointing at the SL order, the SL record carriestpOrderpointing at the TP order). Trigger orders surface display type strings such as"Stop Market","Take Profit Market","Take Profit Limit".get_position_history()— closed positions. Response wraps inpositionskey, includeshasMorefor pagination.get_position_history(symbol=..., start_time=..., end_time=..., limit=..., offset=0)— filtered by symbol and time range. Times in milliseconds (e.g., 7 days =7 * 24 * 3_600_000). Useoffsetfor pagination.
See examples/rest/fetch-balance-updates.py, fetch-my-trades.py, fetch-order-history.py, fetch-position-history.py, fetch-position-history-filtered.py, examples/ws/async-fetch-balance-updates.py, async-fetch-trades-for-position.py.
Important
- Keep scripts minimal and focused on one thing at a time.
- Reference the
examples/directory if the user wants more complete examples.
Next.js App Router Expert
Development
A skill that turns Claude into a Next.js App Router expert.
README Generator
Development
Creates professional and comprehensive README.md files for your projects.
API Documentation Writer
Development
Generates comprehensive API documentation in OpenAPI/Swagger format.