The official Python SDK for the SpecStory API, providing intuitive access to all SpecStory features.
Before using this SDK, you'll need:
-
SpecStory Extension: Install one or more SpecStory extensions in your development environment
- Learn more: SpecStory Introduction
-
SpecStory Cloud Account: Create an account to obtain your API key
- Quick start guide: SpecStory Cloud Quickstart
- Sign up at: cloud.specstory.com
-
Python: Version 3.9 or higher
pip install specstoryUntil the package is published to PyPI, you can install directly from GitHub:
# Install directly from GitHub
pip install git+https://github.com/specstoryai/specstory-cloud-sdk-python.git
# Or clone and install locally for development
git clone https://github.com/specstoryai/specstory-cloud-sdk-python.git
cd specstory-cloud-sdk-python
pip install -e .First, create a .env file in your project root:
# .env
SPECSTORY_API_KEY=your-api-key-hereImportant: Add .env to your .gitignore file to keep your API key secure.
Then use the SDK:
import os
from specstory import Client
# Load environment variables from .env file
# You may need to: pip install python-dotenv
from dotenv import load_dotenv
load_dotenv()
# Initialize the client with your API key
# Get your API key from: https://cloud.specstory.com/api-keys
client = Client(
api_key=os.environ["SPECSTORY_API_KEY"], # Required
# Optional: Override base URL for self-hosted instances
# base_url="https://cloud.specstory.com" # Default, override for self-hosted
)
# Search across sessions
results = client.graphql.search("error 500")
print(f"Found {results['total']} results")- π Pythonic: Designed with Python best practices and idioms
- π Type-safe: Full type hints for better IDE support
- π Async support: Both sync and async clients available
- π Auto-retry: Built-in retry logic with exponential backoff
- π¦ Zero dependencies: Only requires standard library (httpx for async)
- π§ͺ Well-tested: Comprehensive test coverage
from specstory import Client
client = Client(
api_key: str, # Your API key (required)
base_url: str = "https://cloud.specstory.com", # API base URL (default)
timeout_s: float = 30.0, # Request timeout in seconds
cache: dict | bool = None, # Cache configuration or False to disable
)from specstory import AsyncClient
import asyncio
async def main():
client = AsyncClient(api_key="your-api-key")
# All methods are async
projects = await client.projects.list()
# Don't forget to close the client
await client.close()
asyncio.run(main())# List projects
projects = client.projects.list(page=1, limit=10)
# Get a project
project = client.projects.get(project_id)
# Create a project
project = client.projects.create(
name="Project Name",
description="Project description"
)
# Update a project
project = client.projects.update(
project_id,
name="New Name"
)
# Delete a project
client.projects.delete(project_id)# List sessions for a project
sessions = client.sessions.list(project_id)
# Read a specific session
session = client.sessions.read(project_id, session_id)
if session:
print(f"Session name: {session['name']}")
print(f"Markdown size: {session['markdownSize']} bytes")
# Get recent sessions across all projects
recent_sessions = client.sessions.recent(10)
# Delete a session
client.sessions.delete(project_id, session_id)
# Get session metadata without content
metadata = client.sessions.head(project_id, session_id)
if metadata and metadata['exists']:
print(f"Last modified: {metadata['lastModified']}")# Search across all sessions
results = client.graphql.search("error 500",
limit=20,
filters={
"projectId": "specific-project-id",
"tags": ["production"]
}
)
print(f"Found {results['total']} matches")
for result in results['results']:
print(f"{result['name']} (rank: {result['rank']})")The SDK provides typed exceptions for better error handling:
from specstory import Client, SpecStoryError, ValidationError
try:
session = client.sessions.read(project_id, session_id)
except ValidationError as e:
# Handle validation errors
print(f"Validation failed: {e.errors}")
except SpecStoryError as e:
# Handle other API errors
print(f"API error: {e.message}")
except Exception as e:
# Handle unexpected errors
print(f"Unexpected error: {e}")from specstory import Client
# Client automatically closes connections
with Client(api_key="your-api-key") as client:
projects = client.projects.list()client = Client(
api_key="your-api-key",
headers={
"X-Custom-Header": "value"
}
)client = Client(
api_key="your-api-key",
timeout=60.0 # 60 seconds
)# Use the paginated iterator for sessions
for session in client.sessions.list_paginated(project_id):
print(f"Session: {session['name']}")
# Process each session without loading all into memory# Get project by name
project = client.projects.get_by_name("My Project")
if project:
print(f"Found project: {project['id']}")import asyncio
from specstory import AsyncClient
async def main():
async with AsyncClient(api_key="your-api-key") as client:
# All methods are async versions of sync client
projects = await client.projects.list()
# Search asynchronously
results = await client.graphql.search("error")
print(f"Found {results['total']} results")
# Concurrent requests
sessions, recent = await asyncio.gather(
client.sessions.list(projects[0]['id']),
client.sessions.recent(5)
)
asyncio.run(main())We welcome contributions! Please see our Contributing Guide for details.
# Clone the repository
git clone https://github.com/specstoryai/specstory-cloud-sdk-python.git
cd specstory-cloud-sdk-python
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run linting
ruff check specstory tests
black --check specstory tests- Python 3.9 or higher
- No runtime dependencies for sync client
- httpx for async client (installed automatically with
pip install specstory[async])
# Enable caching (default)
client = Client(
api_key="your-api-key",
cache={
"max_size": 200, # Cache up to 200 items
"default_ttl": 600.0 # 10 minutes
}
)
# Disable caching
no_cache = Client(
api_key="your-api-key",
cache=False
)# First read
session = client.sessions.read(project_id, session_id)
etag = session.get('etag') if session else None
# Later, check if changed
updated = client.sessions.read(project_id, session_id, if_none_match=etag)
if updated is None:
print("Session has not changed")# Set default timeout
client = Client(
api_key="your-api-key",
timeout_s=60.0 # 60 seconds
)
# Override for specific request
client.sessions.write(
project_id,
name="Large Session",
markdown="# Big content...",
raw_data=large_json_data,
timeout_s=120.0 # 2 minutes for large uploads
)This SDK is distributed under the Apache License 2.0. See LICENSE for more information.
- π§ Email: support@specstory.com
- π¬ Community: Join our Slack
- π Documentation: docs.specstory.com
- π Issues: GitHub Issues