Install
$ agentstack add skill-impertio-studio-speckle-claude-skill-package-speckle-core-api ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
speckle-core-api
Quick Reference
API Surface Overview
| API Layer | Protocol | Endpoint | Purpose | |-----------|----------|----------|---------| | GraphQL | HTTP POST | https:///graphql | All metadata CRUD, subscriptions | | REST Download | HTTP GET | GET /objects/:projectId/:objectId | Download object data (with children) | | REST Download Single | HTTP GET | GET /objects/:projectId/:objectId/single | Download one object (no children) | | REST Upload | HTTP POST | POST /objects/:projectId | Upload serialized objects | | OAuth Token | HTTP POST | POST /auth/token | Exchange auth code or refresh token |
Terminology Mapping (CRITICAL)
| Legacy Term (Deprecated) | Current Term | GraphQL Legacy Type | GraphQL Current Type | |--------------------------|--------------|---------------------|----------------------| | Stream | Project | Stream | Project | | Branch | Model | Branch | Model | | Commit | Version | Commit | Version | | StreamCollaborator | ProjectCollaborator | StreamCollaborator | ProjectCollaborator |
ALWAYS use current terminology (Project, Model, Version) in new code. The legacy types exist for backward compatibility and will be removed in a future release.
Authentication Header Format
Authorization: Bearer
This format applies to BOTH Personal Access Tokens and OAuth2 access tokens, for BOTH GraphQL and REST endpoints.
Auth Scope Table
| Scope | Purpose | |-------|---------| | streams:read | Read project/model/version data | | streams:write | Create/modify/delete projects, models, versions | | profile:read | Read user profile | | profile:email | Access user email | | profile:write | Update user profile | | profile:delete | Delete user account | | tokens:read | List API tokens | | tokens:write | Create/revoke API tokens | | users:read | Search/list users | | apps:read | List registered OAuth apps | | server:setup | Server admin operations |
Critical Warnings
NEVER use legacy queries (stream, branch, commit) in new code -- ALWAYS use current queries (project, model, version). Legacy queries are deprecated and will be removed.
NEVER embed Personal Access Tokens in client-side (browser) JavaScript -- ALWAYS use OAuth2 flow for browser applications. PATs are for server-side scripts and automation only.
NEVER commit tokens to version control -- ALWAYS store tokens in environment variables or secret managers.
NEVER hardcode https://app.speckle.systems/graphql -- ALWAYS make the server URL configurable. Users may run self-hosted Speckle servers.
NEVER use project.object.data GraphQL queries for large object trees -- ALWAYS use the REST endpoint GET /objects/:projectId/:objectId which supports gzip streaming.
NEVER use display names (version_create, model_update) as webhook trigger strings -- ALWAYS use internal legacy names (commit_create, branch_update).
NEVER ignore 429 responses -- ALWAYS read the Retry-After header and implement exponential backoff.
NEVER skip pagination -- ALWAYS implement cursor-based pagination for collections. There is no unlimited query.
GraphQL Endpoint
Connection URL
- Speckle Cloud:
https://app.speckle.systems/graphql - Self-hosted:
https:///graphql
The endpoint accepts standard GraphQL POST requests with JSON body containing query, variables, and optional operationName. An Apollo Sandbox explorer is available when accessing the URL in a browser.
Server Discovery
ALWAYS query serverInfo first to discover server capabilities:
query ServerInfo {
serverInfo {
name
version
canonicalUrl
automateUrl
configuration {
objectSizeLimitBytes
objectMultipartUploadSizeLimitBytes
}
scopes { name description }
authStrategies { id name }
workspaces { workspacesEnabled }
}
}
This query does NOT require authentication.
Authentication
Decision Tree: PAT vs OAuth2
Is this a server-side script, CLI tool, or CI/CD pipeline?
├─ YES → Use Personal Access Token (PAT)
│ - Simple: one header, no flow
│ - Scope to minimal permissions
│ - Rotate periodically
└─ NO → Is this a browser/desktop app with user interaction?
├─ YES → Use OAuth2 + Challenge flow
│ - Register an OAuth app on the server
│ - Redirect user for consent
│ - Exchange code + challenge for token
└─ NO → Is this a Speckle Automate function?
└─ YES → Token is injected by the Automate runtime
- Use the provided token directly
Personal Access Tokens (PATs)
Create: Profile > Settings > Developer > Access Tokens > "New Token"
Use: Include in every request header:
Authorization: Bearer
Resource-scoped tokens: Tokens can be limited to specific projects or workspaces via the limitResources parameter in ApiTokenCreateInput. This restricts the token to only operate on the specified resources.
Security rules:
- ALWAYS apply principle of least privilege (minimal scopes)
- ALWAYS store in environment variables or secret managers
- ALWAYS rotate periodically
- ALWAYS revoke immediately if compromised
OAuth2 + Challenge Flow
Speckle implements a custom OAuth2 variant with a challenge parameter (similar to PKCE).
Flow summary:
- Register app on server (get App ID + App Secret)
- Generate random challenge string, store locally
- Redirect user to
https:///authn/verify// - User authorizes; Speckle redirects to your URI with
access_code - Exchange code for tokens via
POST /auth/token - Use access token; refresh when expired
See [references/examples.md](references/examples.md) for complete code examples.
REST API
The REST API handles ONLY object upload/download. All other operations MUST use GraphQL.
Download Objects (with children)
GET /objects/:projectId/:objectId
Authorization: Bearer
Accept: application/json
Returns the root object AND all children as gzip-compressed stream. Use the referencedObject from a Version to get the full data tree.
Download Single Object
GET /objects/:projectId/:objectId/single
Authorization: Bearer
Returns ONLY the requested object (no children). Useful for inspecting metadata without downloading the tree.
Upload Objects
POST /objects/:projectId
Authorization: Bearer
Content-Type: application/gzip | text/plain | application/json
Returns HTTP 201 on success. ALWAYS check serverInfo.configuration.objectMultipartUploadSizeLimitBytes before uploading.
Standard Send/Receive Workflow
1. Authenticate (PAT or OAuth2)
2. [Send] Serialize objects → POST /objects/:projectId (REST)
3. [Send] Create version → versionMutations.create (GraphQL)
4. [Receive] Get version → project.version (GraphQL) → get referencedObject
5. [Receive] Download objects → GET /objects/:projectId/:objectId (REST)
6. [Receive] Deserialize objects
Pagination
Speckle uses cursor-based pagination for ALL collections:
type SomeCollection {
totalCount: Int!
cursor: String # null when no more pages
items: [SomeType!]! # "objects" for ObjectCollection
}
Rules:
- ALWAYS specify
limit-- there is no default unlimited query - When
cursorisnullin response, there are no more pages ObjectCollectionusesobjectsinstead ofitems(schema inconsistency)- Typical limits: 25 for models/versions, 100 for objects
Rate Limiting
- Identification priority: User ID > Token ID > IP address > "unknown"
- Batched GraphQL: Each operation in a batch counts separately
- Response headers on 429:
Retry-After: milliseconds until next requestX-RateLimit-Reset: ISO timestamp of resetX-RateLimit-Remaining: available points (on success)
Error Handling
GraphQL Errors
{
"errors": [{
"message": "You do not have access to this resource.",
"path": ["project"],
"extensions": { "code": "FORBIDDEN" }
}],
"data": null
}
| Error Code | Meaning | |------------|---------| | FORBIDDEN | Wrong role or missing scope | | UNAUTHENTICATED | Missing or invalid token | | NOT_FOUND | Resource does not exist or no access | | BAD_USER_INPUT | Invalid input parameters |
REST API Errors
| HTTP Code | Meaning | |-----------|---------| | 401 | Unauthorized (no/invalid token) | | 403 | Forbidden (valid token, insufficient permissions) | | 404 | Object not found | | 413 | Payload too large | | 429 | Rate limited (check Retry-After) |
GraphQL Schema Directives
The schema uses custom directives for authorization:
| Directive | Purpose | |-----------|---------| | @hasServerRole(role: SERVER_USER) | Requires minimum server role | | @hasScope(scope: "streams:read") | Requires specific token scope | | @hasScopes(scopes: [...]) | Requires multiple scopes | | @isOwner | Restricts to resource owner |
Webhook Trigger Terminology (CRITICAL)
Webhook triggers STILL use legacy internal names. The display names in the UI differ:
| Internal Name (use THIS) | Display Name (UI only) | |---------------------------|----------------------| | stream_update | projectupdate | | stream_delete | projectdelete | | branch_create | modelcreate | | branch_update | modelupdate | | branch_delete | modeldelete | | commit_create | versioncreate | | commit_update | versionupdate | | commit_receive | versionreceive | | commit_delete | versiondelete | | comment_created | commentcreated | | comment_archived | commentarchived | | comment_replied | commentreplied | | stream_permissions_add | projectpermissionsadd | | stream_permissions_remove | projectpermissionsremove |
API Version Differences (Server 2.x vs 3.x)
| Aspect | Server 2.x | Server 3.x | |--------|-----------|-----------| | Legacy queries | Available (deprecated) | Removal planned | | Current queries | Full support | Full support | | Workspaces | Not available | Available (check serverInfo) | | Webhook triggers | Legacy names only | Legacy names only | | Object REST endpoints | Same | Same |
ALWAYS query serverInfo.version to determine which features are available.
Reference Links
- [references/methods.md](references/methods.md) -- GraphQL schema: queries, mutations, subscriptions
- [references/examples.md](references/examples.md) -- Working GraphQL + REST examples
- [references/anti-patterns.md](references/anti-patterns.md) -- API misuse patterns
Official Sources
- https://docs.speckle.systems/
- https://github.com/specklesystems/speckle-server
- https://github.com/specklesystems/specklepy
- https://speckle.guide/dev/apps.html (legacy OAuth docs)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Impertio-Studio
- Source: Impertio-Studio/Speckle-Claude-Skill-Package
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.