Python client for the Pre.dev Architect API - Generate comprehensive software specifications
Project description
pre.dev API — Python Client
Python client for the Pre.dev API — AI-powered software specs + browser automation.
Features
Specs
- 🚀 Fast Spec: Comprehensive specifications for MVPs and prototypes
- 🔍 Deep Spec: Ultra-detailed specifications for complex systems
- ⚡ Async Spec: Non-blocking async methods with status polling
- 📄 File upload support (PDFs, docs, images as reference context)
Browser automation (NEW)
- 🌐 Browser Tasks: Scrape, fill forms, navigate pages with structured JSON output
- 📡 SSE streaming: Watch execution live — screenshots, plans, actions
- ⏱ Async mode: Fire-and-forget, poll for progress
- 🔁 Retrieval: Get any past task with full timeline for audit/replay
Quality of life
- ✨ Full type hints
- 🛡 Custom exceptions for auth / rate limit / API errors
Installation
pip install predev-api
Quick Start
from predev_api import PredevAPI
# Initialize the predev client with your API key
predev = PredevAPI(api_key="your_api_key_here")
# Generate a fast specification
result = predev.fast_spec(
input_text="Build a task management app with team collaboration"
)
print(result)
File Upload Support
All fast_spec, deep_spec, fast_spec_async, and deep_spec_async methods support optional file uploads. This allows you to provide architecture documents, requirements files, design mockups, or other context files to improve specification generation.
Using File Path (Simplest)
from predev_api import PredevAPI
predev = PredevAPI(api_key="your_api_key")
# Just pass the file path as a string
result = predev.fast_spec(
input_text="Generate specs based on these requirements",
file="path/to/requirements.pdf"
)
Using File-like Objects
# Open and upload a file
with open("architecture.doc", "rb") as f:
result = predev.deep_spec(
input_text="Create comprehensive specs",
file=f
)
# Or pass a file-like object
from io import BytesIO
file_content = BytesIO(b"Design specifications...")
result = predev.fast_spec(
input_text="Generate specs",
file=file_content
)
Supported File Types
- PDF documents (
*.pdf) - Word documents (
*.doc,*.docx) - Text files (
*.txt) - Images (
*.jpg,*.png,*.jpeg)
Response with File Upload
When you upload a file, the response includes:
result = predev.fast_spec(
input_text="Based on the design document",
file="design.pdf"
)
print(result.uploadedFileName) # "design.pdf"
print(result.uploadedFileShortUrl) # "https://api.pre.dev/f/xyz123"
print(result.codingAgentSpecUrl) # Spec for AI systems
print(result.humanSpecUrl) # Spec for humans
Authentication
The Pre.dev API uses API key authentication. Get your API key from the pre.dev dashboard under Settings → API Keys:
predev = PredevAPI(api_key="your_api_key")
API Methods
Synchronous Methods
fast_spec(input_text: str, current_context: Optional[str] = None, doc_urls: Optional[List[str]] = None) -> SpecResponse
Generate a fast specification (30-40 seconds, ~5-10 credits).
Parameters:
input_text(required):str- Description of what you want to buildcurrent_context(optional):str- Existing project contextdoc_urls(optional):List[str]- Documentation URLs to reference (e.g., Stripe docs, framework docs)
Returns: SpecResponse object with complete specification data
Example:
result = predev.fast_spec(
input_text="Build a SaaS project management tool with real-time collaboration"
)
Example with Documentation URLs:
result = predev.fast_spec(
input_text="Build a payment processing integration with Stripe",
doc_urls=["https://stripe.com/docs/api"]
)
# When doc_urls are provided, the response includes zippedDocsUrls:
# result.zippedDocsUrls = [
# ZippedDocsUrl(
# platform="stripe.com",
# masterZipShortUrl="https://api.pre.dev/s/xyz789"
# )
# ]
# These zipped documentation folders can be downloaded and help coding agents
# stay on track by providing complete, up-to-date documentation context.
deep_spec(input_text: str, current_context: Optional[str] = None, doc_urls: Optional[List[str]] = None) -> SpecResponse
Generate a deep specification (2-3 minutes, ~10-50 credits).
Parameters: Same as fast_spec
Returns: SpecResponse object with comprehensive specification data
Example:
result = predev.deep_spec(
input_text="Build a healthcare platform with HIPAA compliance"
)
Asynchronous Methods
fast_spec_async(input_text: str, current_context: Optional[str] = None, doc_urls: Optional[List[str]] = None) -> AsyncResponse
Generate a fast specification asynchronously (returns immediately).
Parameters: Same as fast_spec
Returns: AsyncResponse object with specId for polling
Example:
result = predev.fast_spec_async(
input_text="Build a comprehensive e-commerce platform"
)
# Returns: AsyncResponse(specId="spec_123", status="pending")
deep_spec_async(input_text: str, current_context: Optional[str] = None, doc_urls: Optional[List[str]] = None) -> AsyncResponse
Generate a deep specification asynchronously (returns immediately).
Parameters: Same as fast_spec
Returns: AsyncResponse object with specId for polling
Example:
result = predev.deep_spec_async(
input_text="Build a fintech platform with regulatory compliance"
)
# Returns: AsyncResponse(specId="spec_456", status="pending")
Status Checking
get_spec_status(spec_id: str) -> SpecResponse
Check the status of an async specification generation request.
Parameters:
spec_id(required):str- The specification ID from async methods
Returns: SpecResponse object with current status and data (when completed)
Example:
status = predev.get_spec_status("spec_123")
# Returns SpecResponse with status: "pending" | "processing" | "completed" | "failed"
Listing and Searching Specs
list_specs(limit: Optional[int] = None, skip: Optional[int] = None, endpoint: Optional[Literal["fast_spec", "deep_spec"]] = None, status: Optional[Literal["pending", "processing", "completed", "failed"]] = None) -> ListSpecsResponse
List all specs with optional filtering and pagination.
Parameters:
limit(optional):int- Results per page (1-100, default: 20)skip(optional):int- Offset for pagination (default: 0)endpoint(optional):"fast_spec" | "deep_spec"- Filter by endpoint typestatus(optional):"pending" | "processing" | "completed" | "failed"- Filter by status
Returns: ListSpecsResponse object with specs array and pagination metadata
Examples:
# Get first 20 specs
result = predev.list_specs()
# Get completed specs only
completed = predev.list_specs(status='completed')
# Paginate: get specs 20-40
page2 = predev.list_specs(skip=20, limit=20)
# Filter by endpoint type
fast_specs = predev.list_specs(endpoint='fast_spec')
find_specs(query: str, limit: Optional[int] = None, skip: Optional[int] = None, endpoint: Optional[Literal["fast_spec", "deep_spec"]] = None, status: Optional[Literal["pending", "processing", "completed", "failed"]] = None) -> ListSpecsResponse
Search for specs using regex patterns.
Parameters:
query(required):str- Regex pattern (case-insensitive)limit(optional):int- Results per page (1-100, default: 20)skip(optional):int- Offset for pagination (default: 0)endpoint(optional):"fast_spec" | "deep_spec"- Filter by endpoint typestatus(optional):"pending" | "processing" | "completed" | "failed"- Filter by status
Returns: ListSpecsResponse object with matching specs and pagination metadata
Examples:
# Search for "payment" specs
payment_specs = predev.find_specs(query='payment')
# Search for specs starting with "Build"
build_specs = predev.find_specs(query='^Build')
# Search: only completed specs mentioning "auth"
auth_specs = predev.find_specs(
query='auth',
status='completed'
)
# Complex regex: find SaaS or SASS projects
saas_specs = predev.find_specs(query='saas|sass')
Regex Pattern Examples:
| Pattern | Matches |
|---|---|
payment |
"payment", "Payment", "make payment" |
^Build |
Specs starting with "Build" |
platform$ |
Specs ending with "platform" |
(API|REST) |
Either "API" or "REST" |
auth.*system |
"auth" then anything then "system" |
\\d{3,} |
3+ digits (budgets, quantities) |
saas|sass |
SaaS or SASS |
Response Types
AsyncResponse
@dataclass
class AsyncResponse:
specId: str # Unique ID for polling (e.g., "spec_abc123")
status: Literal['pending', 'processing', 'completed', 'failed']
SpecResponse
@dataclass
class SpecResponse:
# Basic info
_id: Optional[str] = None # Internal ID
created: Optional[str] = None # ISO timestamp
endpoint: Optional[Literal['fast_spec', 'deep_spec']] = None
input: Optional[str] = None # Original input text
status: Optional[Literal['pending', 'processing', 'completed', 'failed']] = None
success: Optional[bool] = None
# Output data (when completed)
uploadedFileShortUrl: Optional[str] = None # URL to input file
uploadedFileName: Optional[str] = None # Name of input file
codingAgentSpecUrl: Optional[str] = None # Spec optimized for AI/LLM systems
humanSpecUrl: Optional[str] = None # Spec optimized for human readers
totalHumanHours: Optional[int] = None # Estimated hours for human developers
# Direct returns (new)
codingAgentSpecJson: Optional[CodingAgentSpecJson] = None # Simplified JSON for coding tools
codingAgentSpecMarkdown: Optional[str] = None # Simplified markdown for coding tools
humanSpecJson: Optional[HumanSpecJson] = None # Full JSON with hours/personas/roles
humanSpecMarkdown: Optional[str] = None # Full markdown with all details
executionTime: Optional[int] = None # Processing time in milliseconds
# Integration URLs (when completed)
predevUrl: Optional[str] = None # Link to pre.dev project
# Documentation (when doc_urls provided)
zippedDocsUrls: Optional[List[ZippedDocsUrl]] = None
# Complete documentation as zipped folders
# Helps coding agents stay on track with full context
# Each entry contains platform name and download URL
# Error handling
errorMessage: Optional[str] = None # Error details if failed
progress: Optional[int] = None # Overall progress percentage (0-100)
progressMessage: Optional[str] = None # Detailed progress message
# Credit usage - available during processing (real-time) and on completion
# Fast spec: ~5-10 credits, Deep spec: ~10-50 credits
creditsUsed: Optional[float] = None # Total credits consumed by this spec generation
Direct Spec JSON structures
@dataclass
class SpecCoreFunctionality:
name: str
description: str
priority: Optional[str] = None
@dataclass
class SpecTechStackItem:
name: str
category: str
@dataclass
class SpecPersona:
title: str
description: str
primaryGoals: Optional[List[str]] = None
painPoints: Optional[List[str]] = None
keyTasks: Optional[List[str]] = None
@dataclass
class SpecRole:
name: str
shortHand: str
@dataclass
class CodingAgentSubTask:
id: Optional[str] = None
description: str = ""
complexity: str = ""
@dataclass
class CodingAgentStory:
id: Optional[str] = None
title: str = ""
description: Optional[str] = None
acceptanceCriteria: Optional[List[str]] = None
complexity: Optional[str] = None
subTasks: Optional[List[CodingAgentSubTask]] = None
@dataclass
class CodingAgentMilestone:
milestoneNumber: int = 0
description: str = ""
stories: Optional[List[CodingAgentStory]] = None
@dataclass
class CodingAgentSpecJson:
title: Optional[str] = None
executiveSummary: str = ""
coreFunctionalities: Optional[List[SpecCoreFunctionality]] = None
techStack: Optional[List[SpecTechStackItem]] = None
techStackGrouped: Optional[Dict[str, List[str]]] = None
milestones: Optional[List[CodingAgentMilestone]] = None
@dataclass
class HumanSpecSubTask:
id: Optional[str] = None
description: str = ""
hours: float = 0
complexity: str = ""
roles: Optional[List[SpecRole]] = None
@dataclass
class HumanSpecStory:
id: Optional[str] = None
title: str = ""
description: Optional[str] = None
acceptanceCriteria: Optional[List[str]] = None
hours: float = 0
complexity: Optional[str] = None
subTasks: Optional[List[HumanSpecSubTask]] = None
@dataclass
class HumanSpecMilestone:
milestoneNumber: int = 0
description: str = ""
hours: float = 0
stories: Optional[List[HumanSpecStory]] = None
@dataclass
class HumanSpecJson:
title: Optional[str] = None
executiveSummary: str = ""
coreFunctionalities: Optional[List[SpecCoreFunctionality]] = None
personas: Optional[List[SpecPersona]] = None
techStack: Optional[List[SpecTechStackItem]] = None
techStackGrouped: Optional[Dict[str, List[str]]] = None
milestones: Optional[List[HumanSpecMilestone]] = None
totalHours: Optional[float] = None
roles: Optional[List[SpecRole]] = None
ListSpecsResponse
@dataclass
class ListSpecsResponse:
specs: List[SpecResponse] # Array of spec objects
total: int # Total count of matching specs
hasMore: bool # Whether more results are available
Examples Directory
Check out the examples directory for detailed usage examples.
Documentation
For more information about the Pre.dev Architect API, visit:
Support
For issues, questions, or contributions, please visit the GitHub repository.
Browser Tasks
Run browser automation — navigate, interact, and/or extract data from any web page. Each task navigates a URL, performs actions, and optionally returns typed JSON.
Quick start
from predev_api import PredevAPI
client = PredevAPI(api_key="your_api_key")
result = client.browser_agent([
{
"url": "https://news.ycombinator.com",
"instruction": "Extract the top 5 stories",
"output": {
"type": "object",
"properties": {
"stories": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {"type": "string"},
"points": {"type": "number"},
},
},
},
},
},
}
])
for story in result["results"][0]["data"]["stories"]:
print(f"{story['title']} ({story['points']} pts)")
Three execution modes
1. Sync (default) — wait for completion
result = client.browser_agent([
{"url": "https://example.com", "output": {"type": "object", "properties": {"heading": {"type": "string"}}}}
])
print(result["results"][0]["data"]) # {'heading': 'Example Domain'}
print(result["totalCreditsUsed"]) # 0.1
2. Stream (stream=True) — live timeline via SSE
Yields events as the agent runs. Good for showing progress in a UI.
for msg in client.browser_agent(tasks, stream=True):
e, d = msg["event"], msg["data"]
if e == "task_event":
# navigation | screenshot | plan | action | validation | done
print(f"[{d['type']}]", d.get("data"))
elif e == "task_result":
print(f"Task {d['taskIndex']} done:", d.get("data"))
elif e == "done":
print("Batch complete:", d["totalCreditsUsed"], "credits")
elif e == "error":
print("Batch error:", d)
3. Async (run_async=True) — fire-and-forget, poll for progress
Returns the batch ID immediately. Use for long-running batches or background jobs.
import time
r = client.browser_agent(tasks, run_async=True)
# {"id": "batch_abc", "status": "processing", "completed": 0, "total": 3}
while True:
state = client.get_browser_agent(r["id"])
print(f"{state['completed']}/{state['total']}")
for done in state["results"]:
print(f" ✓ {done['url']} -> {done.get('data')}")
if state["status"] == "completed":
break
time.sleep(1)
Task shapes
Each task's behavior is determined by which fields are set:
| Fields | Shape | Example |
|---|---|---|
url + output |
Scrape | Extract structured data from a page |
url + instruction |
Act | Click, navigate, search |
url + instruction + input |
Form fill | Fill & submit a form |
url + instruction + output |
Act + extract | Navigate then extract data |
Retrieving a batch with the full timeline
Every task records navigation, screenshots, LLM plans, actions, validations. Retrieve for audit, replay, or debugging. Screenshots are uploaded to a CDN during execution — retrieved events contain data["url"], not base64.
details = client.get_browser_agent(batch_id, include_events=True)
for result in details["results"]:
for ev in result.get("events", []):
if ev["type"] == "screenshot":
# ev["data"]["url"] is a permanent CDN URL. Use directly in an <img>.
print(f"Iter {ev.get('iteration')} screenshot:", ev["data"]["url"])
elif ev["type"] == "plan":
print(f"Iter {ev.get('iteration')} plan: {ev['data'].get('notes')}")
Note: The live SSE stream (
stream=True) still sends screenshots inline as base64 (ev["data"]["base64"]) so live UIs render instantly. The retrieval path (get_browser_agent) always returns CDN URLs.
Parallel batch example
# Scrape 100 URLs with 20 browsers in parallel
urls = [...100 urls...]
result = client.browser_agent(
[{"url": u, "output": {"type": "object", "properties": {"title": {"type": "string"}}}} for u in urls],
concurrency=20
)
print(f"{result['completed']}/{result['total']} done in {result['totalCreditsUsed']} credits")
Browser task methods
| Method | Returns | Use when |
|---|---|---|
browser_agent(tasks, concurrency=N) |
dict | Default — wait for completion |
browser_agent(tasks, stream=True) |
iterator of SSE dicts | Live UI showing execution timeline |
browser_agent(tasks, run_async=True) |
dict (empty results, returned immediately) | Long batches, background jobs |
get_browser_agent(batch_id, include_events=False) |
dict | Poll progress or retrieve a completed batch |
Task result statuses
| Status | Meaning |
|---|---|
SUCCESS |
Task completed, data extracted |
BLOCKED |
Page blocked automation (bot detection) |
TIMEOUT |
Task exceeded time limit |
LOOP |
Agent detected it was stuck in a loop |
ERROR |
Unexpected error |
NO_TARGET |
Could not find target elements |
CAPTCHA_FAILED |
CAPTCHA solve failed |
Pricing
- Minimum: 0.1 credits per task ($0.01)
- 10x margin on underlying LLM + sandbox compute
- 1 credit = $0.10
Error handling
The browser-task endpoints raise typed exceptions for the most common
gating cases. Every billing-gate exception carries an action_url — a
deep link back to pre.dev that auto-opens the right modal (subscribe /
buy credits) when the user lands there:
from predev_api import (
PredevAPI,
InsufficientCreditsError,
SubscriptionRequiredError,
RateLimitError,
QueueFullError,
)
import webbrowser
client = PredevAPI(api_key="your_pre.dev_api_key")
try:
client.browser_agent([{"url": "https://example.com", "instruction": "extract h1"}])
except InsufficientCreditsError as e:
# Send the user to the credits modal — `action_url` is the canonical link.
if e.action_url:
webbrowser.open(e.action_url)
except SubscriptionRequiredError as e:
if e.action_url:
webbrowser.open(e.action_url)
except RateLimitError:
pass # back off and retry
except QueueFullError:
pass # wait for in-flight tasks to drain
Mid-stream errors on the SSE stream raise the same typed exceptions, so a
for msg in client.browser_agent(..., stream=True): loop wrapped in
try/except is enough — no special event handling required.
| Exception | HTTP | code |
|---|---|---|
SubscriptionRequiredError |
402 | SUBSCRIPTION_REQUIRED |
InsufficientCreditsError |
402 | INSUFFICIENT_CREDITS |
RateLimitError |
429 | RATE_LIMITED |
QueueFullError |
429 | QUEUE_FULL |
BatchTooLargeError |
400 | BATCH_TOO_LARGE |
AuthenticationError |
401 | — |
PredevAPIError |
other | — |
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file predev_api-1.1.0.tar.gz.
File metadata
- Download URL: predev_api-1.1.0.tar.gz
- Upload date:
- Size: 22.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98e093f1440076277e99f15b052228164d8f870b43c8d80d638bb9ed8a13024b
|
|
| MD5 |
fe439d59ba80a44bb702d0c081acf484
|
|
| BLAKE2b-256 |
5b66f8cb18c5529c72c089a65f53d059af252e0fc462d5d6c4a7b6a3cbd55d2a
|
File details
Details for the file predev_api-1.1.0-py3-none-any.whl.
File metadata
- Download URL: predev_api-1.1.0-py3-none-any.whl
- Upload date:
- Size: 17.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23098b125582abf14f7e5a96f06f3a61b5db588d8380ea0ecdc98e4465745379
|
|
| MD5 |
8640feed5629f34540f3f0bbc62940e0
|
|
| BLAKE2b-256 |
872ede2363a0b0fc4f7b289b9056012c33939204ddc70b0e15ad589b518d2c58
|