Pose CLI Documentation
Open motion-analysis toolkit for sports scientists. Analyze 3D skeleton data with 20+ built-in tools, or build your own — all running locally on your machine.
Overview
Pose CLI turns raw 3D body-skeleton data — from ARKit or any pose-estimation system — into actionable sports analytics. It runs entirely on your machine: your data never leaves your computer.
Available on PyPI: Pose CLI is distributed via PyPI. See Installation for details.
Pose Coach Recording → JointData3D CSV → Pose CLI → JSON Output
│
├── stats
├── detect_peak_energy
├── segment_motion_phases
├── detect_velocity
├── detect_action_boundaries
├── detect_highlight
├── annotate (web UI)
└── ... 15+ more
Built-in Lightweight Backend
Pose CLI includes pose serve — a zero-config local server that turns your computer into a development backend for the Pose Coach iOS app:
pose serve # → http://0.0.0.0:8000 # → LAN → http://192.168.1.x:8000 (configure this on iPhone)
Requires pip install 'pose-platform[server]' (installs fastapi + uvicorn). See Installation →
Record on iPhone → skeleton files arrive on your computer automatically. Analysis, AI coach chat, training plans, and comprehensive reports all work through the same local server. The Pose Coach iOS app connects to pose serve as a full-featured backend. No database, no cloud required. Setup guide →
How Data Gets to Pose CLI
Three ways to get recordings from an iPhone (Pose Coach) to your computer:
Path A — Manual Transfer (zero setup, always works)
iPhone Record → Files App → iCloud Drive or AirDrop → Computer → pose analyze ✅ All regions ✅ Full session folder (video + skeleton + sidecar) ⚠ Manual per-session • iCloud Drive: Export folder via Files App → syncs to computer via iCloud • AirDrop: Export All Data → ZIP with all session files sent directly (Mac only)
Path B — Local Backend (one command, automatic)
iPhone Record → Your Computer (WiFi, pose serve) → pose analyze ✅ All regions ✅ Auto upload + analysis + chat 🔧 pip install pose-platform[server,llm] (TestFlight build required — Researcher Backend in Settings)
Path C — Cloud Backend (US/EU only)
iPhone Record → Staging API (auto upload) → pose data seed-session → Computer → pose analyze ✅ Automated ❌ CN not accessible ⚠ .mov not included
| Path | Setup | Network | Regions | What you get |
|---|---|---|---|---|
| A. Manual | None | iCloud or AirDrop | All | Full session (video + skeleton + sidecar) |
| B. Local Backend | pose serve | Same WiFi | All | Skeleton + sidecar (auto per-recording) |
| C. Staging | Backend access | Internet (US/EU) | US/EU only | Skeleton + sidecar (auto per-recording) |
Recommended: Start with AirDrop (Path A) for your first session — instant, no setup. For frequent recording, set up Path B with a single command: pose serve. Full local backend setup guide →
Recording for Unsupported Sports
If you want to analyze a sport that Pose Coach doesn't officially support yet (e.g., basketball, golf, tennis):
- Open Pose Coach → select Freeplay as the sport
- Record as usual — you'll get full 3D skeleton data
- Transfer the data to your computer (Path A or B above)
- Use Pose CLI's generic tools (
stats,segment_motion_phases,detect_action_boundaries,detect_highlight) to analyze - Build sport-specific tools on top — see Contributing
Who is this for?
| You are... | You can... |
|---|---|
| Sports scientist / researcher | Analyze motion data, publish papers, build new analysis tools |
| Coach / performance analyst | Evaluate technique, track progress, compare athletes |
| Movement science student | Learn biomechanics through hands-on data analysis |
| Developer / lab | Build custom tools, integrate with existing pipelines |
Sports as Plugins
Pose CLI uses Python entry_points to auto-discover sport packages. Built-in sports (freeplay, sprint) ship with the base install. Additional sports are installed as independent pip packages:
# Built-in (always available) pose version # → sports: freeplay, sprint # Install badminton — separate package maintained by badminton researchers pip install pose-platform[badminton] # → installs pose-sport-badminton (v1.13.4, 8 tools) # Or install the sport package directly pip install pose-sport-badminton # Create your own sport package pose sports create basketball # → generates sports/basketball/ scaffold with example tool # → pip install -e sports/basketball # → pose tools --sport basketball # List installed sports pose sports
| Sport | Package | Install |
|---|---|---|
| freeplay | built-in | default |
| sprint | built-in | default |
| badminton | pose-sport-badminton | pip install pose-platform[badminton] |
| basketball (template) | create via pose sports create | pip install -e sports/basketball |
| your sport | your package | pip install pose-sport-<name> |
For researchers: Sport packages are independent PyPI packages maintained by domain experts. Each has its own version, release cycle, and maintainer. See Contributing →
Web Annotation Tool
Label recordings interactively in your browser with synchronized video + 2D skeleton overlay:
pose annotate serve data/session.csv # → opens http://localhost:8001
Click and drag on the timeline to mark actions (sprint phases, swings, shots). Annotations serve as ground truth for calibration and algorithm validation.
Prerequisites
The web annotator needs both the skeleton CSV AND the original video (.mov). Video is included via iCloud Drive or AirDrop (Path A), but NOT via local backend or staging (Paths B/C).
Interface
- Left panel: Video player with 2D skeleton overlay (15 bones, 21 joints) + playback controls
- Right panel: Annotations list + creation form (start/end time, label, quality, notes)
CLI Commands
# Create an annotation pose annotate create data/session.csv --start 2.3 --end 3.1 --label "sprint_drive" # List all annotations pose annotate list data/session.csv # Open the web UI pose annotate serve data/session.csv
Calibration Workflow
- Annotate recordings (web or CLI) —
pose annotate serve - Auto-score annotated strokes —
pose calib auto-label - Review and correct scores (expert review)
- Validate tool agreement —
pose calib validate
Key Principles
- Your data stays local. All analysis runs on your machine. No cloud upload required.
- Built-in local backend.
pose servegives you a full development backend — iPhone auto-upload, analysis, and AI chat all work locally. - One tool, all products. Build a tool once — it works in CLI, Pose Coach app, or your custom app.
- Extensible by design. Every tool is a Python class. Write your own, register it, and it's available everywhere.
- Cache built-in. Analysis results are automatically cached. Re-run the same file → instant result.
Quickstart — 5 Minutes
Get from zero to your first analysis.
Step 1: Install
pip install pose-platform pose version
Step 2: Get sample data
Pose CLI ships with a sample sprint recording — no download needed:
pose sample # → sample_sprint.csv copied to current directory (438 KB)
Step 3: Run your first analysis
pose analyze sample_sprint.csv --tool stats
You'll see a JSON report with recording duration, frame rate, joint count, jitter ratio, data quality assessment, and per-joint statistics.
data_quality: "good"— tracking is reliabletracking_coverage: 0.98— 98% of frames have valid skeleton datajitter_ratio < 0.1— excellent stability
Step 4: Try more tools
# Find motion segments (running vs standing)
pose analyze sample_sprint.csv --tool segment_motion_phases
# Detect velocity peaks
pose analyze sample_sprint.csv --tool detect_velocity --param joint=body_position
# Extract highlight moments
pose analyze sample_sprint.csv --tool detect_highlight --param sport_id=sprint
# Measure running speed with athlete profile
pose analyze sample_sprint.csv --tool measure_running_speed \
--param age=16 --param gender=male --param region=cn
Step 5: Use your own data
pose analyze /path/to/your/data.csv --tool stats
Point pose analyze at your own JointData3D CSV. See Data Format for how to prepare data from other pose-estimation systems.
Step 6: Record your own data with Pose Coach
The easiest way to get JointData3D files is to record with the Pose Coach iOS app.
On Windows? Skip straight to "Automatic uploads" below — pose serve runs natively on Windows and avoids AirDrop entirely.
Quick start (no setup):
- Install Pose Coach via TestFlight (ask us for an invitation)
- Record a session — select Freeplay as the sport
- Transfer data to your computer:
- AirDrop (fastest, macOS only — Windows has no AirDrop client): playback menu → Export All Data → AirDrop to your Mac
- iCloud Drive (works on Windows too): tap export → Save to Files → iCloud Drive → install iCloud for Windows (Microsoft Store), sign in with the same Apple ID, then grab the file from the synced local folder
- Run
pose analyzeon the_3d.csvfile
Automatic uploads (one command, recommended for Windows):
- Install with server extras:
pip install 'pose-platform[server,llm]'
- Start the local backend:
pose serve # → LAN → http://192.168.1.x:8000
- In Pose Coach Settings → Researcher Backend → Custom URL → enter your computer's LAN IP
- Record — skeleton files arrive automatically in your
pose-data/directory - Analysis and AI coach chat work directly in the app (routed to your local server)
Installation
Requirements
| Dependency | Minimum | Recommended |
|---|---|---|
| Python | 3.10 | 3.12+ |
| pip | 22.0 | 24.0+ |
| OS | macOS 12+ / Linux (glibc 2.28+) / Windows WSL2 | |
| Disk | ~500 MB (with dependencies) | |
Method 1: pip (recommended)
pip install pose-platform pose version
Method 2: From Source (for tool developers)
git clone https://github.com/posecap/pose-platform.git cd pose-platform pip install -e .
The -e flag installs in "editable" mode — changes to source take effect immediately.
Method 3: Virtual Environment
python3 -m venv pose-env source pose-env/bin/activate # macOS / Linux # pose-env\Scripts\activate # Windows pip install pose-platform
Optional Dependencies
# Sport packages — install domain-specific analysis tools pip install 'pose-platform[badminton]' # Badminton: swing detection, stroke classification, scoring # pip install 'pose-platform[basketball]' # Basketball (future) # All sports pip install 'pose-platform[all-sports]' # Local backend (pose serve) — receive iPhone uploads + run analysis server pip install 'pose-platform[server]' # LLM chat (pose chat) — three modes available pip install 'pose-platform[llm]' # REPL mode (openai SDK) pip install 'pose-platform[mcp]' # Claude Code mode (mcp SDK, >=1.0,<2.0) # Everything — all sports + backend + AI chat pip install 'pose-platform[all]' # Claude Code frontend (optional, for --mode claude / --mode claude-ds) npm install -g @anthropic-ai/claude-code
| Extra | Includes | Used by |
|---|---|---|
| [badminton] | pose-sport-badminton | Badminton analysis |
| [all-sports] | all sport packages | Multi-sport research |
| [server] | fastapi, uvicorn, python-multipart | pose serve |
| [llm] | openai, anthropic | pose chat, pose serve /chat |
| [mcp] | mcp>=1.0,<2.0 | pose chat --mode claude / --mode claude-ds |
| [all] | all-sports + server + llm | Full installation |
Troubleshooting
pip: command not found
python3 -m ensurepip --upgrade
error: externally-managed-environment (macOS Homebrew Python)
Use a virtual environment (Method 3) or:
pip install --break-system-packages pose-platform
pose: command not found after pip install
# Add to ~/.zshrc or ~/.bashrc
export PATH="$HOME/.local/bin:$PATH"
# Windows (native install) — locate the Scripts folder:
python -c "import sysconfig; print(sysconfig.get_path('scripts'))"
# → e.g. C:\Users\you\AppData\Roaming\Python\Python312\Scripts
# Add that folder to PATH (System Properties → Environment Variables), then restart the terminal.
# Alternative on any OS — run without the pose command
python3 -m products.pose_cli.cli version # python on Windows
Apple Silicon (M1/M2/M3)
The platform works natively on ARM. Verify with:
python3 -c "import platform; print(platform.machine())" # Should print: arm64
Windows
WSL2 is recommended. Native Windows also works — if pose isn't found after pip install, add Python's Scripts folder to PATH (see the "pose: command not found" item above).
wsl --install wsl # Then follow Linux instructions above
pose chat starts but exits with "HTTP API key not set"
pose chat needs the openai package and an API key:
pip install openai>=1.50 echo 'POSE_DEEPSEEK_API_KEY=sk-xxx' > .env # free tier: platform.deepseek.com pose chat
Data Format — JointData3D
This is the most important concept to understand before using Pose CLI. Every tool reads JointData3D CSV files.
⚠️ Important: Understanding the difference between world coordinates and model coordinates is critical for correct analysis. See below.
The 12-Column Format
Pose CLI expects CSV files without headers. Each row represents one joint at one timestamp.
timestamp, joint, wx, wy, wz, mx, my, mz, ldq_x, ldq_y, ldq_z, ldq_w
| # | Column | Type | Description |
|---|---|---|---|
| 1 | timestamp | float | Seconds since recording start |
| 2 | joint | int or string | Joint identifier (name or index) |
| 3–5 | wx, wy, wz | float | World position (ARKit world-anchor coordinates) |
| 6–8 | mx, my, mz | float | Model position (relative to body center-of-mass) |
| 9–12 | ldq_x … ldq_w | float | Local rotation quaternion (x, y, z, w) |
World vs. Model Coordinates
| Coordinate System | Source | Use Case | Stability |
|---|---|---|---|
| wx, wy, wz | ARKit world anchor | Absolute court position, heatmaps | ⚠️ Can drift across sessions |
| mx, my, mz | Body center-of-mass relative | Joint angles, relative motion, technique | ✅ Stable within a session |
Rule of thumb: Use model coordinates (mx/my/mz) for all biomechanical analysis. All built-in tools default to model coordinates.
Data Quality Checklist
jitter_ratio< 0.3 (runpose analyze data.csv --tool stats)tracking_coverage> 0.5 (skeleton was tracked for most of the recording)- Recording distance 2–8 meters from camera (ARKit optimal range)
- Full body visible (not occluded by objects or other people)
- Single person in frame (ARKit only tracks one body)
- Device is stationary (tripod recommended)
Preparing Data from Other Systems
If you use OpenPose, MediaPipe, BlazePose, or motion capture, convert your data to the 12-column format. Key requirements:
- Timestamps: monotonically increasing, seconds from start
- Joint order: must match the 19-joint ARKit body skeleton (or use string names)
- Model coordinates: if unavailable, set equal to world coords (some tools will have reduced accuracy)
- Quaternions: if unavailable, set
ldq_x=0, ldq_y=0, ldq_z=0, ldq_w=1(identity)
import numpy as np
# Your data: timestamps (T,), joint_names list, world_positions (T, J, 3)
for t_idx, t in enumerate(timestamps):
for j_idx, jname in enumerate(joint_names):
wx, wy, wz = world_positions[t_idx, j_idx]
mx, my, mz = world_positions[t_idx, j_idx] # or compute model coords
# Identity quaternion: no rotation data
print(f"{t},{jname},{wx},{wy},{wz},{mx},{my},{mz},0,0,0,1")
CLI Command Reference
All commands run locally. No network required for analysis commands.
pose analyze
Run a tool on a JointData3D CSV file.
pose analyze <file.csv> [--tool <name>] [--no-cache] [--param KEY=VALUE ...]
| Option | Description |
|---|---|
| <file.csv> | JointData3D CSV file path (required) |
| --tool <name> | Tool to run (default: stats) |
| --no-cache | Skip cache, force recomputation |
| --param KEY=VALUE | Pass parameter to tool (repeatable). Auto-detects type |
| --env <env> | Backend environment: local, staging, or prod (default: auto-detect) |
| --subject-id <ID> | For training plan stagnation detection (requires POSE_API_TOKEN) |
# Basic analysis
pose analyze data/session.csv
# Specific tool
pose analyze data/session.csv --tool detect_peak_energy
# With parameters
pose analyze data/session.csv --tool measure_running_speed \
--param age=16 --param gender=male --param region=cn
# Force recomputation
pose analyze data/session.csv --tool stats --no-cache
pose tools
List all registered tools with version numbers.
pose tools # Compact table: Name, Version, Status, Sport, Description pose tools --detail # Full parameter details for each tool pose tools --sport <id> # Filter by sport (e.g., badminton, sprint)
pose sample
Copy the bundled sample data file (sample_sprint.csv) to the current directory. No network required — the sample is included in the pip package.
pose sample # → sample_sprint.csv copied to current directory (438 KB) # → Next: pose analyze sample_sprint.csv --tool stats
pose sports
Manage sports: list installed sports, add custom sports, or create new sport packages.
pose sports list # Built-in + installed sport packages (default) pose sports add <id> # Add a custom sport (writes .pose/config.json) pose sports remove <id> # Remove a custom sport pose sports create <id> # Generate new sport package scaffold
Installing sport packages: Additional sports are distributed as independent pip packages. Install via pip extras or directly:
pip install pose-platform[badminton] # or pip install pose-sport-badminton
Creating a new sport: Use pose sports create to scaffold, then install in editable mode:
pose sports create basketball # → generates sports/basketball/ with pyproject.toml, example tool, tests pip install -e sports/basketball pose tools --sport basketball
pose gaps
Manage the capability gap registry — track feature requests and tool ideas locally.
pose gaps list # Active gaps pose gaps list --all-statuses # All including resolved pose gaps submit "<title>" # Register a new gap pose gaps show <gap_id> # View gap details + temp implementation pose gaps summary # Statistical summary
pose cache
Manage analysis result cache. Cache invalidates automatically when source file or tool version changes.
pose cache list # All cached entries pose cache clear # Clear all cache pose cache clear <file.csv> # Clear cache for specific file
pose version
Display version information — dynamically detects installed sport packages.
pose version # Platform + installed sports pose version --changelog # Technical changelog (CHANGELOG.md) pose version --release-notes # User-facing release notes
Example output:
{
"platform": "1.25.10",
"sports": {
"freeplay": {"version": "1.25.10", "builtin": true},
"sprint": {"version": "1.25.10", "builtin": true},
"badminton": {"version": "1.13.4", "builtin": false, "tools_count": 8}
}
}
pose chat
Start an interactive LLM-powered analysis session. Requires the [llm] extra (pip install openai) and an API key. See LLM Chat for setup.
pose chat [data_dir] # Default data dir: ../pose-data
pose annotate
Create, list, and delete annotations for a recording. Also launches the web annotation UI.
pose annotate create <file.csv> --start <s> --end <s> --label <name>
[--peak_s <s>] [--hand left|right]
[--quality good|acceptable|poor] [--note "text"]
pose annotate list <file.csv>
pose annotate delete <file.csv> <annotation_id>
pose annotate serve <file.csv> # Web annotation UI
pose calib
Score calibration workflow — compare tool scores against expert annotations to validate algorithm accuracy.
pose calib auto-label # Auto-score annotated strokes pose calib validate # Validate tool agreement against expert labels
| Metric | Description |
|---|---|
| MAE | Mean Absolute Error between tool scores and expert labels |
| Spearman ρ | Rank correlation — how well tool preserves ordering |
| Grade agreement | Fraction where tool grade matches expert grade (±1 letter tolerance) |
pose feedback
Submit and manage feedback items — bug reports, feature requests, and tool improvement suggestions.
pose feedback list # List all feedback pose feedback stats # Summary statistics pose feedback resolve <id> # Mark as resolved pose feedback dismiss <id> # Dismiss with reason
pose telemetry
pose telemetry stats # Today's stats pose telemetry stats --since 7d # Last 7 days pose telemetry stats --since 24h # Last 24 hours
pose data
Manage local data files.
pose data delete <file> [--yes] [--dry-run]
Tool Reference
Pose CLI has 20+ built-in tools. Below are the three primary general-purpose tools. Sport-specific tools are documented in the full repository.
stats
stable Tier 1 · All sports · Since v1.4.0Computes comprehensive statistics for a JointData3D recording. Run this first on any new data — it's your data quality report card.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| path | string | — | JointData3D CSV file path |
| video_duration_s | float | (auto) | Override recording duration |
Key Output Fields
| Field | Description |
|---|---|
| recording_duration_s | Total recording time |
| tracking_coverage | Fraction of frames with valid skeleton (< 0.5 = poor) |
| jitter_ratio | Fraction of frames with high jitter (< 0.1 = good, > 0.3 = poor) |
| data_quality | Summary: "good", "acceptable", or "poor" |
| per_joint.<name>.motion_std | Standard deviation of model-coordinate movement |
pose analyze data/session.csv --tool stats
detect_action_boundaries
stable Tier 1 · All sports · Since v1.1.0Detects action boundaries — start, peak, and end of discrete movements — using full-body energy analysis. Works on any sport without tuning.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| onset_energy_ratio | float | 0.01 | Energy threshold ratio for action onset |
| max_filter_win_s | float | 1.0 | Window for max-energy smoothing |
| prominence | float | 0.1 | Minimum peak prominence |
| min_action_duration_s | float | 0.2 | Minimum action duration |
| min_peak_gap_s | float | 0.5 | Minimum time between detected actions |
Output Fields
| Field | Description |
|---|---|
| actions[].start_s | Action onset — when body energy starts rising |
| actions[].peak_s | Moment of maximum energy |
| actions[].end_s | Action ends — energy returns to baseline |
| actions[].peak_energy | Normalized energy at peak (1.0 = max in recording) |
| actions[].duration_s | Total action duration |
# Basketball — find jumps, shots, drives
pose analyze data/basketball_play.csv --tool detect_action_boundaries \
--param min_action_duration_s=0.2 --param min_peak_gap_s=0.3
# Sprint — find drive phases
pose analyze data/sprint_100m.csv --tool detect_action_boundaries \
--param onset_energy_ratio=0.01
When to use this vs. sport-specific tools: Use detect_action_boundaries for exploring new data or unsupported sports. Use sport-specific tools when you need per-action classification (smash vs. clear, jump shot vs. layup).
segment_motion_phases
stable Tier 1 · All sports · Since v1.5.0Decomposes a recording into three hierarchical layers: presence segments, motion/static segments, and pauses. Essential for understanding session rhythm.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| presence_gap_s | float | 1.0 | Max timestamp gap before splitting presence segments |
| static_threshold | float | 0.03 | Energy threshold for static classification |
| min_static_ms | int | 500 | Minimum duration for a valid static segment |
| min_motion_ms | int | 300 | Minimum duration for a valid motion segment |
| pause_prominence | float | 0.5 | Sensitivity for detecting pauses within motion |
| energy_filter | string | "mean" | "mean" or "max" — smoothing filter |
| max_filter_win_s | float | 1.0 | Window size for energy filter |
| motion_trailing_pad_s | float | 0.3 | Extra tail padding on motion segments |
Output Fields
| Field | Description |
|---|---|
| presence_segments | Continuous periods with a person in frame |
| motion_segments | Periods of activity (swinging, running, jumping) |
| static_segments | Periods of stillness (standing, waiting) |
| pauses | Brief stops within an otherwise active segment |
| summary.motion_ratio | Fraction of presence time spent in motion |
pose analyze data/basketball_drill.csv --tool segment_motion_phases
Tips: Use energy_filter="max" for explosive sports (sprint, basketball drive). Default "mean" works well for sustained motion. Combine with detect_action_boundaries to find specific action peaks within motion segments.
Environment Variables
Analysis & Data
| Variable | Default | Description |
|---|---|---|
| POSE_DATA_DIR | ../pose-data | Directory for data files |
| POSE_ENABLE_WIP_TOOLS | 0 | Set to 1 to enable work-in-progress tools |
| POSE_PLATFORM_SPORTS | (empty) | Additional platform sports. Format: badminton:v1.0.0,fitness:v1.13.0. Set on Pose Coach backend to expose sports beyond the CLI baseline |
LLM Providers (for pose chat)
| Variable | Provider | Description |
|---|---|---|
| ANTHROPIC_API_KEY | Claude (Anthropic) | API key from console.anthropic.com |
| POSE_DEEPSEEK_API_KEY | DeepSeek | API key from platform.deepseek.com (free tier available) |
| POSE_DEEPSEEK_API_ENDPOINT | DeepSeek | Override base URL (default: https://api.deepseek.com) |
| POSE_CN_API_KEY | Qwen (DashScope) | API key from dashscope.aliyun.com |
| POSE_CN_API_ENDPOINT | Qwen (DashScope) | Override base URL. Use https://dashscope-intl.aliyuncs.com/compatible-mode/v1 for international access |
Chat Mode
| Variable | Default | Description |
|---|---|---|
| POSE_CHAT_MODE | repl | Chat frontend mode: repl (built-in + DeepSeek), claude (Claude Code + Claude), claude-ds (Claude Code + DeepSeek). CLI --mode flag overrides |
Region & Language
| Variable | Default | Description |
|---|---|---|
| POSE_REGION | us | LLM routing region: us, eu, cn, or cloud |
| POSE_LANG | (auto-detect) | Output language. Auto-detected from LANG/LC_ALL |
Caching
Pose CLI caches tool results to avoid recomputing the same analysis. The cache key is: file identity (mtime + size) + tool name + tool version.
Cache Invalidation
Cache is automatically invalidated when the source file changes (mtime/size) or the tool version changes in pose-manifest.json. Tool upgrades automatically invalidate old caches.
Cache Commands
pose cache list # All cached entries pose cache clear # Clear all cache pose cache clear <file.csv> # Clear cache for specific file
Skip cache with pose analyze data.csv --tool stats --no-cache. Cache HIT is indicated with [CACHE HIT] in CLI output.
CI/CD Integration
In CI pipelines, cache the .pose/cache/ directory. Cache key on pose-manifest.json hash gives correct invalidation on tool version bumps.
LLM-Powered Analysis (pose chat)
Pose CLI includes an AI chat mode that lets you ask natural-language questions about your data. The default provider is DeepSeek — free tier, email signup, global access.
Quick Setup
Install the LLM extra and create a .env file — Pose CLI loads it automatically. No export, no source needed.
pip install 'pose-platform[llm]' echo 'POSE_DEEPSEEK_API_KEY=sk-xxx' > .env pose chat
Get a free DeepSeek API key at platform.deepseek.com.
Providers
DeepSeek (default)
Free tier, email signup. Works globally.
echo 'POSE_DEEPSEEK_API_KEY=sk-xxx' > .env pose chat
Claude (best quality)
Requires Anthropic API key. Optional Claude Code CLI shell.
export ANTHROPIC_API_KEY=sk-ant-... pose chat
Claude Code shell (optional): npm install -g @anthropic-ai/claude-code
Qwen / DashScope (Chinese-optimized)
export POSE_REGION=cn export POSE_CN_API_KEY=sk-xxx pose chat
Chat Modes
pose chat supports three frontend modes. Switch via --mode flag or POSE_CHAT_MODE environment variable.
| Mode | Frontend | Backend | Setup |
|---|---|---|---|
| repl | Built-in REPL | DeepSeek | [llm] + key |
| claude | Claude Code CLI | Claude native | Claude Code + [mcp] |
| claude-ds | Claude Code CLI | DeepSeek | Claude Code + [mcp] + key |
# REPL mode (default) pose chat # Claude Code + Claude native (best experience) npm install -g @anthropic-ai/claude-code pip install 'pose-platform[mcp]' pose chat --mode claude # Claude Code + DeepSeek echo 'POSE_DEEPSEEK_API_KEY=sk-xxx' > .env pose chat --mode claude-ds
How it works
pose chat reads POSE_DEEPSEEK_API_KEY and automatically injects the following into Claude Code's environment before launching it:
| Claude Code env var | Value |
|---|---|
| ANTHROPIC_BASE_URL | https://api.deepseek.com/anthropic |
| ANTHROPIC_AUTH_TOKEN | $POSE_DEEPSEEK_API_KEY |
| ANTHROPIC_MODEL | deepseek-v4-pro[1m] |
This bridges DeepSeek's Anthropic-compatible API endpoint to Claude Code's native authentication model. You only need POSE_DEEPSEEK_API_KEY — the translation is handled transparently.
Note: If you launch Claude Code directly (without pose chat), you must set ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN yourself. pose chat --mode claude-ds does this for you automatically.
When using --mode claude or --mode claude-ds, Pose CLI also automatically generates a temporary .mcp.json that connects Claude Code to the pose-analysis MCP server with all registered tools — no manual setup needed.
Region Routing
The default configuration uses DeepSeek for all regions. You can override via pose-manifest.json or environment variables.
# Default routing: # US/EU region: DeepSeek (http_api) → Claude (fallback if configured) # CN region: Qwen-Plus (http_api) → DeepSeek (fallback) # Force a region: export POSE_REGION=cn # CN routing (requires manifest config) export POSE_REGION=us # US routing (default)
Example Session
> How many action segments are in this recording? [Tool: detect_action_boundaries] Found 14 action segments > What was the fastest one? [Tool: detect_velocity] Peak at 2.3s, 18.5 m/s > Analyze the running gait pattern [Tool: analyze_running_gait] Cadence: 180 spm, symmetry: 0.94, ...
Local Backend Setup
Record motion data with Pose Coach on an iPhone and have skeleton files automatically land on your computer — no cloud, no staging server, no Mac required.
pose servepose-data/pose analyze data.csvPrerequisites
- iPhone with Pose Coach installed via TestFlight (ask us for an invitation link)
- Computer with Pose CLI installed (
pip install -e .in the pose_platform repo) - Both devices on the same WiFi network
Step 1: Start the Local Backend
# Install with server extras (if not already) pip install 'pose-platform[server,llm]' # Start the backend pose serve # → http://0.0.0.0:8000 # → LAN → http://192.168.1.x:8000 (configure this on iPhone) # → data → /Users/you/pose-data
The server listens on all network interfaces by default. Your LAN IP is printed automatically — use it to configure the iPhone. Options: pose serve --port 9000, pose serve --data-dir ~/my-data.
Step 2: Configure Pose Coach on iPhone
- Open Pose Coach on your iPhone
- Go to Settings (gear icon)
- Scroll to Researcher Backend section
- Select Custom URL
- Enter
http://<YOUR_IP>:8000(e.g.,http://192.168.1.42:8000) - Tap Apply
- Restart the app when prompted
Note: The Researcher Backend section is visible in TestFlight builds automatically.
Step 3: Record & Analyze
- In Pose Coach, select Freeplay as the sport (use this for any sport not yet officially supported)
- Record your motion — skeleton CSV is automatically uploaded after stopping
- Files land in your
pose-data/directory
# Check what arrived ls pose-data/*_3d.csv | tail -5 # Run analysis pose analyze pose-data/20260723T140000_seg_1_iPhone_3d.csv --tool stats pose analyze pose-data/20260723T140000_seg_1_iPhone_3d.csv --tool segment_motion_phases pose analyze pose-data/20260723T140000_seg_1_iPhone_3d.csv --tool detect_action_boundaries
Step 4 (Optional): Get the Video File
The .mov video is not uploaded to the backend (privacy guarantee). To get it:
- After recording in Pose Coach, tap the export button (share icon)
- Choose Save to Files → iCloud Drive
- On your computer, download from iCloud Drive
- The
.movvideo pairs with the_3d.csvskeleton (same filename stem)
Supported Endpoints
pose serve implements 20+ API endpoints compatible with the Pose Coach iOS app:
| Endpoint | Method | Purpose |
|---|---|---|
| /health /health/strict | GET | Health check |
| /auth/anonymous | POST | Anonymous auth (returns JWT) |
| /auth/refresh | POST | Token refresh |
| /user/me | GET | User profile |
| /sports | GET | Sport list |
| /capabilities | GET | Tool list + gaps |
| /tools | GET | Tool definitions |
| /models/{sport} | GET | AFM model status |
| /upload | POST | Receive recordings |
| /sessions | GET | Session list |
| /sessions/metadata | POST | Auto-generate title/summary |
| /analyze | POST | Run analysis tools |
| /chat | POST | AI coach chat |
| /chat/stream | POST | SSE streaming chat |
| /subjects | GET | Subject list |
| /subjects/{id}/sessions | GET | Subject's sessions |
| /subjects/{id}/progress | GET | Progress data |
| /generate_report | POST | Comprehensive report |
| /generate_subject_training_plan | POST | Cross-session training plan |
| /annotations/status | POST | Annotation status |
| /corrections | POST | Skeleton corrections |
| /ios/feature-flags | GET | Feature flags |
What pose serve provides vs the cloud backend
| Feature | pose serve |
Cloud Backend |
|---|---|---|
| File upload | ✅ | ✅ |
| Analysis (all tools) | ✅ | ✅ |
| AI Coach chat | ✅ | ✅ (SSE streaming) |
| Training plan (per-session) | ✅ | ✅ |
| Training plan (comprehensive) | ✅ | ✅ |
| Comprehensive report | ✅ | ✅ |
| Session history | ✅ (in-memory) | ✅ (database) |
| Subject profiles | ✅ | ✅ |
| User accounts | ❌ | ✅ |
| Multi-device | ❌ | ✅ |
| Database | ❌ | ✅ |
Troubleshooting
"Cannot connect to backend" on iPhone
- Verify both devices are on the same WiFi network
- Check firewall: allow incoming connections on port 8000
- On Windows: allow Python through Windows Firewall
"Upload failed" after recording
Confirm pose serve is still running and the data directory exists and is writable.
Backend not showing in Settings
Make sure you're using the TestFlight version of Pose Coach (not App Store). The Researcher Backend section appears automatically in TestFlight builds.
Switching back to normal use
Settings → Researcher Backend → switch to Staging (or Production) → Apply → restart the app.
Contributing
Pose CLI is designed to be extended. Build new tools, add sport support, or contribute code.
Building a New Tool
A tool is a Python class. Write it once, register it, and it works everywhere — CLI, Pose Coach app, custom apps.
Step 1: Create the tool class in capabilities/tools/my_tool.py
from capabilities.tools.base import DirectTool
from capabilities.tools.loader import load_pose
import json
from pathlib import Path
class MyTool(DirectTool):
name = "my_tool"
description = "What this tool does"
input_schema = {
"type": "object",
"properties": {
"path": {"type": "string", "description": "CSV file path"},
"my_param": {"type": "number", "default": 1.0},
},
"required": ["path"]
}
status = "wip" # "wip" or "stable"
supported_sports = [] # [] = all sports
tier = 1 # 1 = primary, 2 = fallback
depends_on = [] # Optional: tool dependencies
requires_session_context_by_sport = ["badminton"] # Optional: sport-specific metadata
def run(self, tool_input: dict, output_dir: Path) -> str:
pose = load_pose(tool_input["path"])
result = {"your_field": 42}
return json.dumps(result, ensure_ascii=False)
Step 2: Register in capabilities/tools/registry.py — add import and instance to all_tools list.
Step 3: Enable and test:
export POSE_ENABLE_WIP_TOOLS=1 pose tools | grep my_tool pose analyze data/test.csv --tool my_tool
Extending Sport Support
Add a new sport in 3 lines:
# pose_platform_core/sports_catalog.py
OFFICIAL_SPORTS = [
# ... existing ...
SupportedSport(id="basketball", since_version="1.24.0"),
]
Now build tools with supported_sports = ["basketball"]. Generic tools work automatically.
Promoting a Tool to Stable
- Write unit tests (≥ 1) —
pytest tests/unit/ - Test with 10+ real recordings
- Test edge cases (empty data, single frame, missing joints)
- Add documentation in
docs/features/<tool_name>.md - Change
status = "stable"in your tool class - Add version entry in
pose-manifest.json→tools
Distributing Your Tools
Two ways to distribute your custom tools:
| Path 1: Sport Package | Path 2: Merge into Platform | |
|---|---|---|
| Best for | Sport-specific tool collections | General-purpose tools |
| Distribution | Independent PyPI package | Part of pose-platform |
| Versioning | Your own version + release cycle | Follows platform releases |
| How to | pose sports create <id> then publish | PR to posecap/pose-platform |
Data Loading Best Practices
- Use
pose.mpoints(model coordinates) for biomechanical analysis - Oreason filtering is automatic —
load_pose()excludes anomalous frames - Use
pose.joint_namesto look up joint indices dynamically - Return
data_qualityin your output to help users assess reliability - Bump the tool version in
pose-manifest.jsonwhen algorithms change — old cache auto-invalidates
License
Pose CLI — Motion Analysis Toolkit · Copyright © 2026 PoseCap Inc. All rights reserved.
1. Research License (Non-Commercial)
Academic researchers, educational institutions, and individual learners are granted a royalty-free, non-exclusive, non-transferable license to use, modify, and create derivative works for non-commercial research and educational purposes, subject to:
- Attribution — Any publication must cite the Pose Platform (BibTeX citation below)
- No Redistribution — You may not redistribute the software or its core algorithms without prior written consent
- No Commercial Use — You may not embed in commercial products, provide paid services, or sell access to analysis results
- Modifications — Tools and extensions you develop are your own IP. Contributing grants PoseCap Inc. a license to use and distribute your contributions
2. Commercial License
Any commercial use requires a separate written agreement with PoseCap Inc. Contact contact@posecap.com for commercial licensing.
Citation
If you use Pose CLI in your research, please cite:
@software{pose_platform,
title = {Pose Platform: Open Motion Analysis Toolkit},
author = {{PoseCap Inc.}},
year = {2026},
url = {https://github.com/posecap/pose-platform},
}
Disclaimer
This software is provided "AS IS", without warranty of any kind, express or implied. In no event shall the authors or copyright holders be liable for any claim, damages or other liability arising from the use of the software.
Ready to analyze your motion data?
Pose CLI is available on PyPI — install and start analyzing in minutes. Email us and tell us what you want to study.