{
  "format": "siebly-agent-implementation-manifest/v1",
  "id": "bybit-position-manager",
  "title": "Bybit Manual Position Manager Agent Manifest",
  "task": "bybit-manual-position-manager",
  "version": 1,
  "lastReviewed": "2026-05-01",
  "purpose": "Single start file for coding agents building a Bybit manual position manager. Use it before coding to avoid Binance terminology leaks and Bybit runtime traps.",
  "canonicalArtifacts": {
    "manifest": "https://siebly.io/.well-known/agent-manifests/bybit-position-manager/latest.json",
    "conformancePack": "https://siebly.io/.well-known/conformance/bybit-position-manager/latest.json",
    "guide": "https://siebly.io/ai/position-manager/bybit",
    "recipe": "https://siebly.io/.well-known/recipes/bybit-position-manager.json",
    "integrationKit": "https://siebly.io/.well-known/integration-kits/bybit-position-manager/latest.json",
    "sdkGuide": "https://siebly.io/sdk/bybit/typescript",
    "bybitTutorial": "https://siebly.io/sdk/bybit/javascript/tutorial",
    "agentSkill": "https://siebly.io/.well-known/agent-skills/siebly-crypto-exchange-api/SKILL.md"
  },
  "authorityOrder": [
    "Use this manifest to build the first local checklist.",
    "Use the integration kit as the compact source for field matrices, event policy, retCode handling, command safety, and fixture names.",
    "Use the recipe and guide for explanatory context.",
    "Use installed bybit-api package declarations and current Bybit API docs as the final authority for exact request shapes."
  ],
  "package": {
    "ecosystem": "npm",
    "name": "bybit-api",
    "install": "npm install bybit-api",
    "versionPolicy": "Use the latest available bybit-api package. Record the installed version for source verification only; installed declarations and current docs are the authority for exact request shapes.",
    "docs": "https://siebly.io/sdk/bybit/typescript",
    "repository": "https://github.com/tiagosiebler/bybit-api"
  },
  "requiredFirstSteps": [
    "Install the latest available dependencies and record the installed bybit-api package version as metadata.",
    "Run or create the local source-verification script.",
    "Write SOURCE_VERIFICATION.md with exact methods, types, files, examples, and package version checked.",
    "Generate a short implementation checklist from this manifest and the integration kit before editing exchange code.",
    "Implement dry-run planning and conformance fixtures before demo/live submission."
  ],
  "criticalPath": [
    "Install the latest available bybit-api package and record the installed version as source-verification metadata only.",
    "Verify RestClientV5, WebsocketClient, subscribeV5(...), private order/execution/position/wallet topics, lifecycle events, closeAll(true), and REST method names from installed declarations before coding.",
    "Start with read-only REST hydration and dry-run DCA/TP/SL intents. Live order placement, amend, and cancel remain disabled until explicit demo or live gates are enabled and reviewed.",
    "Hydrate instruments, account mode, wallet, positions, active orders, recent orders, executions, and risk limits before planning.",
    "Connect private account-level WebSockets only after scope and credentials are explicit. Buffer private events until REST hydration and replay are complete.",
    "Serialize each category/symbol/positionIdx product workflow so reconciliation, replay, planning, and submission cannot overlap.",
    "Classify every REST order, amend, cancel, and pre-check response by retCode === 0 unless throwExceptions is intentionally enabled.",
    "Use deterministic orderLinkId values for app-owned DCA, TP, SL, replacement, cancel, and amend lifecycles. Preflight duplicate, recent, and in-flight IDs before the first exchange call.",
    "For linear conditional SL orders, include triggerDirection, triggerBy, orderFilter=StopOrder, reduceOnly, closeOnTrigger, and positionIdx after verifying current request types.",
    "Normalize hydrated Bybit active-order defaults before desired-vs-active comparison so accepted app-owned orders converge to intentCount=0 instead of cancel/recreate churn.",
    "Use demoTrading=true and testnet=false as the default exchange execution environment when demo order placement is requested. Do not use Bybit WebSocket API order commands for demo trading."
  ],
  "criticalLiveConformance": {
    "conformancePack": "https://siebly.io/.well-known/conformance/bybit-position-manager/latest.json",
    "mustPassBeforeLive": [
      "bybit_manual_open_reacts_without_timer",
      "bybit_retcode_nonzero_aborts_batch",
      "bybit_conditional_sl_requires_trigger_direction",
      "bybit_hydrated_defaults_do_not_churn",
      "bybit_duplicate_order_link_id_preflights_batch",
      "bybit_accepted_submissions_settle_to_zero_intents",
      "bybit_deferred_replan_owner_only",
      "bybit_private_stream_exception_prevents_service_ready"
    ]
  },
  "sourceVerificationScript": {
    "filename": "scripts/verify-bybit-position-manager-surfaces.mjs",
    "command": "node scripts/verify-bybit-position-manager-surfaces.mjs",
    "scriptLines": [
      "import { createRequire } from 'node:module';",
      "const require = createRequire(import.meta.url);",
      "const pkg = require('bybit-api/package.json');",
      "const bybit = await import('bybit-api');",
      "const requiredExports = ['RestClientV5', 'WebsocketClient'];",
      "const report = {",
      "  package: 'bybit-api',",
      "  installedVersion: pkg.version,",
      "  exports: Object.fromEntries(requiredExports.map((name) => [name, Boolean(bybit[name])])),",
      "  manualInspectionTargets: ['submitOrder', 'cancelOrder', 'amendOrder', 'preCheckOrder', 'getInstrumentsInfo', 'getPositionInfo', 'getActiveOrders', 'getHistoricOrders', 'getExecutionList', 'getWalletBalance', 'getAccountInfo', 'getRiskLimit', 'subscribeV5', 'closeAll', 'orderLinkId', 'positionIdx', 'triggerDirection', 'closeOnTrigger', 'orderFilter', 'retCode'],",
      "};",
      "console.log(JSON.stringify(report, null, 2));",
      "if (!report.exports.RestClientV5 || !report.exports.WebsocketClient) process.exitCode = 1;"
    ],
    "requiredFollowUp": "After the script runs, manually inspect installed declarations for method signatures, category values, private subscription shape, retCode response types, order request fields, lifecycle events, and closeAll(force?) shape."
  },
  "mustVerifyInstalledSdk": {
    "clients": [
      "RestClientV5",
      "WebsocketClient"
    ],
    "privateTopics": [
      "order",
      "execution",
      "position",
      "wallet"
    ],
    "privateEvents": [
      "open",
      "response",
      "update",
      "reconnect",
      "reconnected",
      "exception"
    ],
    "restMethods": [
      "getInstrumentsInfo",
      "getPositionInfo",
      "getActiveOrders",
      "getHistoricOrders",
      "getExecutionList",
      "getWalletBalance",
      "getAccountInfo",
      "getRiskLimit",
      "submitOrder",
      "cancelOrder",
      "amendOrder",
      "preCheckOrder"
    ],
    "declarationTargets": [
      "RestClientV5",
      "WebsocketClient",
      "CategoryV5",
      "NewOrderParamsV5",
      "OrderResultV5",
      "APIResponseV3WithTime",
      "WSOrderEventV5",
      "WSExecutionEventV5",
      "WSPositionEventV5",
      "WSWalletEventV5"
    ],
    "fields": [
      "orderLinkId",
      "positionIdx",
      "triggerDirection",
      "triggerBy",
      "orderFilter",
      "closeOnTrigger",
      "reduceOnly",
      "retCode",
      "retMsg"
    ]
  },
  "requestBuilders": {
    "linearDcaLimit": {
      "clientIdField": "orderLinkId",
      "requiredFields": [
        "category",
        "symbol",
        "side",
        "orderType",
        "qty",
        "price",
        "positionIdx"
      ],
      "optionalOmitWhenUndefined": [
        "triggerPrice",
        "triggerDirection",
        "triggerBy",
        "orderFilter"
      ],
      "notes": [
        "Do not send trigger-only fields for plain limit DCA orders."
      ]
    },
    "linearTakeProfit": {
      "clientIdField": "orderLinkId",
      "requiredFields": [
        "category",
        "symbol",
        "side",
        "orderType",
        "qty",
        "price",
        "reduceOnly",
        "positionIdx"
      ],
      "notes": [
        "Verify current reduce-only semantics for the selected category and account mode."
      ]
    },
    "linearStopLoss": {
      "clientIdField": "orderLinkId",
      "requiredFields": [
        "category",
        "symbol",
        "side",
        "orderType",
        "qty",
        "triggerPrice",
        "triggerDirection",
        "triggerBy",
        "orderFilter",
        "reduceOnly",
        "closeOnTrigger",
        "positionIdx"
      ],
      "notes": [
        "Long SL below current price uses triggerDirection=2.",
        "Short SL above current price uses triggerDirection=1.",
        "Verify current quantity and close-on-trigger requirements before live use."
      ]
    }
  },
  "skeletonModules": [
    {
      "path": "src/config.ts",
      "responsibility": "Environment, product scope, dry-run/demo/live gates, per-symbol DCA/TP/SL settings."
    },
    {
      "path": "src/bybit/sourceVerification.ts",
      "responsibility": "Installed package and declaration verification report."
    },
    {
      "path": "src/bybit/clientFactory.ts",
      "responsibility": "RestClientV5/WebsocketClient construction with explicit demo/testnet/live settings."
    },
    {
      "path": "src/bybit/restHydration.ts",
      "responsibility": "Instruments, account mode, wallet, positions, active orders, history, executions, risk limits."
    },
    {
      "path": "src/bybit/privateStreams.ts",
      "responsibility": "Private order/execution/position/wallet subscription, buffering, lifecycle events, shutdown."
    },
    {
      "path": "src/state/productWorkflow.ts",
      "responsibility": "Per-category/symbol/positionIdx owner workflow, deferred reasons, replay, planning, submission."
    },
    {
      "path": "src/planner/positionPlanner.ts",
      "responsibility": "Manual position detection, lifecycle epoch, DCA generation, desired order intents."
    },
    {
      "path": "src/planner/orderComparison.ts",
      "responsibility": "Bybit desired-vs-hydrated normalization and replacement decisions."
    },
    {
      "path": "src/execution/bybitSubmitter.ts",
      "responsibility": "retCode classification, duplicate orderLinkId preflight, provisional accepted orders, pauses."
    },
    {
      "path": "src/logging/redaction.ts",
      "responsibility": "Structured sanitized logs and secret redaction."
    }
  ],
  "gotchas": [
    "Do not copy Binance newClientOrderId, clientAlgoId, positionSide, closePosition, USD-M Algo methods, or private-stream helper names into Bybit code.",
    "A resolved REST promise with retCode !== 0 is not success when throwExceptions is false.",
    "Missing triggerDirection on a Bybit conditional SL can reject only the SL while later TP/DCA orders continue if the batch is not aborted. Abort on first rejection.",
    "Hydrated active orders include explicit defaults that can look different from desired request objects. Normalize by order kind before replacement.",
    "Account-level WebSocket idleness is normal. Pause on lifecycle exceptions, reconnects, failed subscribe responses, rejected live calls, or conflicting state, not on quiet traffic alone.",
    "Bybit demo trading and testnet are separate environment choices. Do not enable both by accident."
  ],
  "finalAcceptanceGate": [
    "SOURCE_VERIFICATION.md exists and references Bybit surfaces, not Binance surfaces.",
    "Critical conformance fixtures pass locally before demo/live submission can be enabled.",
    "README documents dry-run, demo, and live environment flags, including demoTrading=true/testnet=false demo default.",
    "Private stream and workflow scheduling tests prove no recursive pause/replan reason logspam.",
    "Live order placement remains disabled until explicit user configuration and reviewed code."
  ]
}
