원클릭으로
oura-setup
Connect an Oura Ring via OAuth2 — app registration, token exchange, and credential storage
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Connect an Oura Ring via OAuth2 — app registration, token exchange, and credential storage
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Read, search, send, and manage messages across Gmail, Outlook, Telegram, and other platforms
An on-demand personal daily briefing — weather, headlines, the shape of your day, and one thing worth your attention — in a sharp executive-assistant voice. The general-purpose morning brief; richer work or admin digests compose it as their general layer.
One-time migration of an existing memory-v2 concept corpus into the memory-v3 section-grain "wiki" — topical articles with a stand-alone lead and queryable sections — with loss-proof staging, assistant-reviewed authoring, and a retrieval-eval gate before cutover.
Delegate a big or high-stakes job to a fleet of parallel subagents, orchestrated deterministically; runs unattended and reports back
Manage contacts, communication channels, access control, and invite links
Build and edit small, personal visual tools and artifacts — dashboards, trackers, calculators, data visualizations, charts, simple landing pages, and slide decks the user wants for THEMSELVES. This is the right skill whenever the user asks to "visualize this," "make a chart," or "build an artifact" for their own use, or to edit an app they already built here. Do NOT reach for a ui_show dynamic_page to fake an artifact — build a real persistent app here. NOT for complex, multi-user, or shippable products — those go to a real project folder with a coding agent (see Scope below).
| name | oura-setup |
| description | Connect an Oura Ring via OAuth2 — app registration, token exchange, and credential storage |
| compatibility | Designed for Vellum personal assistants |
| metadata | {"emoji":"💍","vellum":{"category":"health","display-name":"Oura Ring Setup"}} |
Connect the user's Oura Ring to pull sleep, heart rate, readiness, activity, and other health data via the Oura Cloud API V2.
Have the user go to https://developer.ouraring.com/applications and create a new application:
http://localhost:3000/callbackpersonal, daily, heartrate, sleep, workout, spo2, stress, heart_health, session, ring_configurationSave the Client ID and Client Secret.
Store the client secret securely using assistant credentials prompt, then write and run the OAuth helper script on the user's machine:
#!/usr/bin/env python3
"""Oura Ring OAuth2 helper — catches auth code and exchanges for tokens instantly."""
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs, urlencode
import urllib.request, json, webbrowser, ssl
CLIENT_ID = 'YOUR_CLIENT_ID'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'
REDIRECT_URI = 'http://localhost:3000/callback'
SCOPES = 'email personal daily heartrate workout tag session spo2 ring_configuration stress heart_health'
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
parsed = urlparse(self.path)
if parsed.path == '/':
params = urlencode({
'response_type': 'code', 'client_id': CLIENT_ID,
'redirect_uri': REDIRECT_URI, 'scope': SCOPES, 'state': 'assistant'
})
self.send_response(302)
self.send_header('Location', f'https://cloud.ouraring.com/oauth/authorize?{params}')
self.end_headers()
elif parsed.path == '/callback':
code = parse_qs(parsed.query).get('code', [''])[0]
if code:
token_data = urlencode({
'grant_type': 'authorization_code', 'code': code,
'redirect_uri': REDIRECT_URI, 'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
}).encode()
try:
req = urllib.request.Request('https://api.ouraring.com/oauth/token',
data=token_data,
headers={'Content-Type': 'application/x-www-form-urlencoded'},
method='POST')
resp = urllib.request.urlopen(req, context=ssl.create_default_context())
result = json.loads(resp.read())
with open('/tmp/oura_tokens.json', 'w') as f:
json.dump(result, f, indent=2)
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.end_headers()
self.wfile.write(b'<html><body><h1>Connected! You can close this tab.</h1></body></html>')
print(f'\nTokens saved to /tmp/oura_tokens.json')
except Exception as e:
self.send_response(500)
self.end_headers()
self.wfile.write(f'Token exchange failed: {e}'.encode())
def log_message(self, *a): pass
print('Opening browser for Oura authorization...')
webbrowser.open('http://localhost:3000')
HTTPServer(('localhost', 3000), Handler).serve_forever()
Run with python3 /path/to/script.py on the user's machine (host_bash). The user authorizes in their browser, the script catches the code and exchanges it for tokens in under a second.
Important: Auth codes expire in ~30 seconds. Do NOT have the user paste codes manually — use this script to catch and exchange them automatically.
After the OAuth flow, read tokens from /tmp/oura_tokens.json and store them:
access_token — store in credential vault with injection template for api.ouraring.com Authorization header (Bearer prefix) and allowed_tools: ["bash"]refresh_token — store in credential vault for token refreshTest with the personal info endpoint:
curl -s -H "Authorization: Bearer $TOKEN" "https://api.ouraring.com/v2/usercollection/personal_info"
All endpoints use GET https://api.ouraring.com/v2/usercollection/{type} with query params start_date and end_date (YYYY-MM-DD format).
| Endpoint | Data | Notes |
|---|---|---|
/v2/usercollection/daily_sleep | Sleep score, duration, efficiency, stages | Best checked after user's typical wake time |
/v2/usercollection/sleep | Detailed sleep periods with HR, HRV, movement | Raw sleep period data |
/v2/usercollection/daily_readiness | Readiness score, HRV balance, recovery | Good morning check-in metric |
/v2/usercollection/daily_activity | Steps, calories, movement, inactivity | Activity summary |
/v2/usercollection/heartrate | Continuous HR (use start_datetime/end_datetime in ISO format) | Can be large — limit date range |
/v2/usercollection/daily_spo2 | Blood oxygen levels | Nightly average |
/v2/usercollection/daily_stress | Stress score and recovery | Daytime stress tracking |
/v2/usercollection/workout | Detected workouts with HR, calories | Auto-detected or manual |
/v2/usercollection/personal_info | Age, weight, height, email | Good connection test |
Tokens expire after 30 days. Refresh with:
curl -s -X POST "https://api.ouraring.com/oauth/token" \
-d "grant_type=refresh_token&refresh_token=$REFRESH_TOKEN&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET"
Store the new access_token and refresh_token from the response.