A Bittensor subnet for decentralized semantic video moment retrieval.
ChronoSeek enables semantic search over video content by mapping natural-language scene descriptions to precise timestamp intervals within a video.
Current Status: Fully functioning on testnet with a released developer-facing gateway.
This repository implements the ChronoSeek 1.0 subnet currently running on testnet.
1.0 Capabilities:
- Multimodal baseline: Miners perform visual retrieval plus transcript-based speech understanding. Vision remains the primary signal, and speech-derived scoring acts as an additional boost when audio is available and usable.
- Deterministic evaluation: Validators evaluate against ActivityNet Captions annotations loaded from Hugging Face or a local manifest, with accessible/inaccessible video caching to keep synthetic validation usable on testnet.
- Scoring: Validators score miners by best-match Intersection-over-Union (IoU) in
[0, 1], maintain moving averages for weight setting, and normalize weights on-chain. A strict IoU threshold of0.5remains only for local pass/fail verification scripts. - Gateway/API: Validators can expose a protocol-compatible gateway for application and developer traffic, and that developer-facing surface is already released.
- Deployment status: Miner search, validator scoring, and gateway request flows are all functioning on testnet.
Roadmap (2.0+):
- Full multimodality: Extend from vision + speech transcript matching to vision + speech + non-speech sound understanding.
- Stronger retrieval models: Transition from the current CLIP-based baseline toward more temporal-aware architectures like Moment-DETR or VideoLlama-class systems.
- Richer evaluation and incentives: Expand beyond the current deterministic dataset loop once more advanced generation and scoring are trustworthy.
- Caching and modular inference: Add stronger caching and optional delegated inference backends where they improve real testnet performance.
This project is organized into the following key documents:
-
Problem Statement
Why this subnet exists, the "dark data" problem, and the limitations of current search tools. -
System Design
Technical architecture, including the deployed Miner/Validator logic, validator gateway behavior, and longer-term multimodal roadmap. -
Business Logic & Market Rationale
Market size ($94B+), commercialization strategy, and competitive advantage against centralized giants.
We are building a decentralized protocol where:
- Miners use AI models (CLIP, Transformers) to "watch" videos and find specific moments.
- Validators run deterministic ActivityNet evaluation to grade miners and serve organic/developer requests.
- Miners currently combine visual search with transcript-based speech understanding.
- Users get precise timestamps (e.g., "04:12 - 04:18") for natural language queries.
User / Client
│
▼
Validator (Scoring + Gateway)
├─ Deterministic evaluation (scoring & weights)
└─ Organic / developer query routing
│
▼
Miners
└─ Semantic video analysis (vision + speech transcript scoring)
This project uses poetry for dependency management.
- Python 3.12+
- Poetry installed
git clone https://github.com/chronoseek/bittensor-subnet.git
cd bittensor-subnet
# Install dependencies and create virtualenv
poetry installpoetry env activateTo download models (e.g., CLIP), you need a Hugging Face token.
- Get your token at huggingface.co/settings/tokens.
- Set it in your environment:
export HF_TOKEN=your_token_hereOr add it to your .env file.
ChronoSeek miner uses yt-dlp for platform URLs (YouTube, Vimeo, etc.).
For YouTube reliability, install at least one JS runtime and optionally provide cookies from a logged-in browser.
- Node.js 22+ (recommended), or
- Deno 2+
Example install commands (Ubuntu):
# Node 22 via nvm
nvm install 22
nvm use 22
# Deno (optional alternative)
curl -fsSL https://deno.land/install.sh | shThen set runtime paths in .env (use whichever you installed):
CHRONOSEEK_YTDLP_NODE_PATH=/home/<user>/.nvm/versions/node/v22.x.x/bin/node
CHRONOSEEK_YTDLP_DENO_PATH=/home/<user>/.deno/bin/deno- Export cookies from a browser session that can play the target video
(Netscape formatcookies.txt; extensions like "Get cookies.txt LOCALLY" work). - Save it outside version control (for example:
/home/<user>/secrets/cookies.txt). - Point miner to the file:
CHRONOSEEK_YTDLP_COOKIES=/home/<user>/secrets/cookies.txtAlternative (desktop/local only):
CHRONOSEEK_YTDLP_COOKIES_BROWSER=chrome
# or: firefox:DefaultNotes:
CHRONOSEEK_YTDLP_COOKIEStakes precedence overCHRONOSEEK_YTDLP_COOKIES_BROWSER.- Never commit cookies files.
cookies.txtis ignored by.gitignore. - Under PM2, start miner with
poetry run python ...so the same virtualenv and dependencies are used.
The miner listens for validator HTTP requests, including signed /search queries and /health liveness checks.
# Starts miner on port 8000
poetry run python miner.pyEnsure your wallet/hotkey is registered on SN298.
The validator generates synthetic tasks, queries miners, and scores them.
# Starts validator loop
poetry run python validator.pyEnsure your wallet/hotkey is registered on SN298.
To run the validator without synthetic evaluation and weight updates (when you want to run only the API for organic request handling):
poetry run python validator.py --no-enable-synthetic-evaluationValidators can optionally expose a public API for application or developer use. This is disabled by default.
Supported endpoints:
GET /healthGET /capabilitiesPOST /searchPOST /search/stream
The /search endpoint accepts the standard ChronoSeek VideoSearchRequest payload and returns a standard VideoSearchResponse. It waits for all queried miners to finish before aggregating and ranking the combined result set. This preserves the existing synchronous behavior for API consumers that want the fullest available aggregate.
The /search/stream endpoint accepts the same request payload and responds as a server-sent event stream. It emits an immediate accepted event once the validator has selected currently healthy miners and dispatched the fanout, then emits result events whenever usable miner responses arrive, followed by a terminal done or error event.
The /capabilities endpoint exposes gateway metadata such as the supported protocol versions so upstream platform services can verify compatibility at startup.
The /health endpoint is intentionally self-identifying. Miner health responses include service: "miner" and validator API health responses include service: "validator-gateway", so validator liveness checks do not confuse one role for the other.
Gateway behavior:
- validators maintain a miner liveness snapshot using periodic
/healthchecks - both search endpoints query several currently healthy miners, ranked by the validator's current moving scores
- synthetic validator scoring also targets only miners that are currently healthy at liveness sweep time
POST /searchaggregates the returned windows across all completed miner queries before respondingPOST /search/streamkeeps the connection open and yields incremental usable results as miner responses arrive- both return the top
kranked windows by confidence in the standardVideoSearchResponse.resultsfield - the response remains compatible with the shared protocol contract here
Example:
poetry run python validator.py \
--enable-validator-api \
--validator-api-host 0.0.0.0 \
--validator-api-port 8010You can test miner.py directly without running a validator by sending a signed
Epistula request to /search with scripts/test_miner_search.py.
# In terminal A: start miner
poetry run python miner.py
# In terminal B: run a signed search request
poetry run python scripts/test_miner_search.py \
--video-url "https://www.w3schools.com/html/mov_bbb.mp4" \
--query "people talking"Optional flags:
--endpoint(default:http://127.0.0.1:8000/search)--top-k(default:3)--wallet-name,--wallet-hotkey,--wallet-path(for Epistula signing key)
For long-running processes, use PM2.
npm install pm2 -gpm2 start "poetry run python miner.py --wallet.name default --wallet.hotkey default" --name minerpm2 start "poetry run python validator.py --wallet.name default --wallet.hotkey default" --name validatorpm2 list
pm2 logs miner
pm2 logs validator| Variable | Description | Default |
|---|---|---|
WALLET_NAME |
Name of your coldkey | default |
HOTKEY_NAME |
Name of your hotkey | default |
WALLET_PATH |
Path to your wallet storage | ~/.bittensor/wallets/ |
NETUID |
Subnet NetUID | 298 (Mainnet TBD) |
NETWORK |
Network (finney, test, local) | test |
PORT |
Default value for axon.port |
8000 |
MIN_VALIDATOR_STAKE |
Minimum validator stake required by the miner | 10000 |
CHRONOSEEK_YTDLP_COOKIES |
Optional path to Netscape cookies.txt for YouTube auth |
`` |
CHRONOSEEK_YTDLP_COOKIES_BROWSER |
Optional browser source for cookies (chrome, firefox:Default, etc.) |
`` |
CHRONOSEEK_YTDLP_NODE_PATH |
Optional Node.js runtime path used by yt-dlp EJS challenge solver | `` |
CHRONOSEEK_YTDLP_DENO_PATH |
Optional Deno runtime path used by yt-dlp EJS challenge solver | `` |
LOG_LEVEL |
Logging verbosity | INFO |
HF_TOKEN |
Hugging Face Token | None |
HF_HOME |
Hugging Face cache directory | ~/.cache/huggingface |
HF_ACTIVITYNET_FILENAME |
Optional filename override inside the ActivityNet snapshot | `` |
TASK_DATASET_PATH |
Optional local validator dataset path | `` |
TASK_SPLIT |
Validator task split | validation |
REQUIRE_ACCESSIBLE_VIDEOS |
Skip inaccessible validator task videos | 1 |
TASK_MAX_SAMPLING_ATTEMPTS |
Max tries to find an accessible validator task | 50 |
VIDEO_AVAILABILITY_CACHE_PATH |
Legacy base path used to derive the validator accessible/inaccessible cache files | `` |
ACCESSIBLE_VIDEO_CACHE_PATH |
JSON cache path for validator videos confirmed to be accessible | `` |
INACCESSIBLE_VIDEO_CACHE_PATH |
JSON cache path for validator videos confirmed to be inaccessible | `` |
VIDEO_AVAILABILITY_CACHE_TTL_HOURS |
TTL for cached video availability checks | 24 |
VIDEO_AVAILABILITY_TIMEOUT |
Timeout for validator-side video availability checks (seconds) | 20 |
ENABLE_SYNTHETIC_EVALUATION |
Enable synthetic validator scoring and on-chain weight updates | 1 |
SYNTHETIC_MINER_TIMEOUT_SECONDS |
Per-miner timeout for synthetic validator evaluation requests | 150 |
ENABLE_VALIDATOR_API |
Enable the optional validator /search, /search/stream, /health, and /capabilities API |
0 |
VALIDATOR_API_HOST |
Host for the optional validator API | 0.0.0.0 |
VALIDATOR_API_PORT |
Port for the optional validator API | 8010 |
VALIDATOR_API_MAX_MINERS |
Max miners queried concurrently per validator API request | 3 |
VALIDATOR_API_SYNC_MINER_TIMEOUT_SECONDS |
Per-miner timeout for sync validator API search fanout | 135 |
VALIDATOR_API_STREAM_MINER_TIMEOUT_SECONDS |
Per-miner timeout for streaming validator API search fanout | 135 |
VALIDATOR_MINER_HEALTH_INTERVAL_SECONDS |
Interval between validator liveness sweeps using miner /health |
60 |
VALIDATOR_MINER_HEALTH_TIMEOUT_SECONDS |
Per-miner timeout for validator liveness checks via miner /health |
5 |