Universal tracker interface, connector SDK, and sync engine for Spec Kitty
Project description
spec-kitty-tracker
Shared task-tracker abstraction layer for Spec Kitty CLI and SaaS.
Scope
- Canonical issue model (
CanonicalIssue,ExternalRef,CanonicalLink) - Tracker connector protocol with capability negotiation
- Doctrine-style source-of-truth ownership policies
- Conflict resolution and deterministic sync engine
- Bidirectional mission/issue sync bridge with decision reference traceability
- Connector registry and vendor connector implementations
Included Connectors
SaaS-Backed (via create_hosted_connector)
LinearConnectorJiraConnectorGitHubConnectorGitLabConnector
Out of Scope for Hosted Transport (this release)
AzureDevOpsConnector
Local/Native (direct construction)
BeadsConnector— local-firstbdCLI adapterFPConnector— local-firstfpCLI adapter
Test/Reference
InMemoryConnector— fully functional reference connector
Installation
pip install -e .
For development tools:
pip install -e ".[dev]"
Quick Example
The primary integration path for SaaS-backed providers (Linear, Jira, GitHub, GitLab) uses create_hosted_connector with host-provided transport context. See Local/Native and Test Connectors for direct construction.
import asyncio
from spec_kitty_tracker import (
create_hosted_connector,
HostedConnectorRequest,
LinearHostedParams,
NangoConnectionContext,
InMemoryIssueStore,
OwnershipPolicy,
OwnershipMode,
SyncEngine,
)
async def main() -> None:
# SaaS host provides identity context per operation
nango_ctx = NangoConnectionContext(
connection_id="user-connection-id",
provider_config_key="linear",
nango_secret_key="nango-secret",
)
# Factory constructs a connector routed through SaaS-owned transport
connector = create_hosted_connector(HostedConnectorRequest(
provider="linear",
nango_context=nango_ctx,
params=LinearHostedParams(team_id="TEAM-UUID"),
))
store = InMemoryIssueStore()
policy = OwnershipPolicy(mode=OwnershipMode.EXTERNAL_AUTHORITATIVE)
engine = SyncEngine(connector=connector, store=store, policy=policy)
async with connector:
await engine.pull()
asyncio.run(main())
Hosted Discovery
The canonical path for downstream hosts to discover provider workspaces and bindable resources is the function-based public API: discover_workspaces and discover_resources. Both are exported from the top-level spec_kitty_tracker package and return typed dataclasses.
import asyncio
from spec_kitty_tracker import (
create_hosted_connector,
discover_resources,
discover_workspaces,
ConnectorRequestError,
DiscoveryContractError,
HostedConnectorRequest,
NangoConnectionContext,
)
from spec_kitty_tracker.discovery.hosted_adapter import (
connector_params_to_hosted_params,
)
async def integrate_linear() -> None:
# 1. Build the per-user transport context. The host owns identity.
nango_ctx = NangoConnectionContext(
connection_id="user-connection-id",
provider_config_key="linear",
nango_secret_key="nango-secret",
)
# 2. Discover workspaces. Catch contract failures separately.
try:
workspaces = await discover_workspaces("linear", nango_ctx)
except DiscoveryContractError as exc:
# Provider returned malformed metadata — alert operators.
print(f"contract violation: {exc.provider} {exc.field_path}")
return
except ConnectorRequestError as exc:
# Network / auth / API error — retryable based on failure_class.
print(f"request failed: {exc}")
return
workspace = workspaces.items[0]
print(f"id={workspace.id} display={workspace.display}")
# Read normalized optional metadata defensively.
metadata = workspace.provider_context or {}
handle = metadata.get("workspace_handle") # str | None
url = metadata.get("workspace_url") # str | None
# 3. Discover bindable resources within the chosen workspace.
resources = await discover_resources("linear", workspace, nango_ctx)
resource = resources.items[0]
routing = resource.routing_metadata
display_key = routing.get("display_key") # str | None
resource_url = routing.get("resource_url") # str | None
# 4. Translate connector_params to typed HostedParams + construct connector.
hosted_params = connector_params_to_hosted_params(
provider=resource.provider,
connector_params=resource.connector_params,
)
connector = create_hosted_connector(HostedConnectorRequest(
provider=resource.provider,
nango_context=nango_ctx,
params=hosted_params,
))
async with connector:
... # Use the connector with SyncEngine, mission_seed_from_issue, etc.
asyncio.run(integrate_linear())
The shape above is identical for linear, jira, github, and gitlab — only the value of the provider argument and the upstream Nango configuration change.
Hybrid metadata contract
Discovery results carry a hybrid metadata schema. Top-level dataclass fields (id, name, display, kind, provider, stable_ref, display_name, etc.) are the canonical source of truth for IDs and labels — they are always present and never duplicated into metadata. The two metadata containers (provider_context on workspaces and routing_metadata on resources) carry provider-native keys plus four optional normalized keys:
| Container | Key | Type | Semantic |
|---|---|---|---|
provider_context |
workspace_handle |
str | None |
Short URL-safe slug for the workspace |
provider_context |
workspace_url |
str | None |
Browser URL pointing to the workspace home |
routing_metadata |
display_key |
str | None |
Short human-readable resource identifier |
routing_metadata |
resource_url |
str | None |
Browser URL pointing to the resource home |
These keys are optional: when a provider has no meaningful value, the key is absent. When present, the type is enforced at runtime by discover_workspaces / discover_resources — a malformed payload raises DiscoveryContractError. Hosts that want generic, cross-provider behavior should prefer top-level fields and the four normalized keys over provider-native extras.
See kitty-specs/006-hosted-discovery-contract-hardening/contracts/discovery-contract.md for the full contract specification, data-model.md for the per-provider expected-keys table, and quickstart.md for the full host integration walkthrough.
Deprecated shim modules
The modules spec_kitty_tracker.workspace_discovery and spec_kitty_tracker.resource_discovery are compatibility-only shims. They re-export the canonical symbols (discover_workspaces, discover_resources, DiscoveredWorkspace, DiscoveredResource, DiscoveryResult) for backward compatibility with older pinned downstream consumers, but they emit a DeprecationWarning on import. New code should import from the top-level package:
# Deprecated — emits DeprecationWarning
from spec_kitty_tracker.workspace_discovery import discover_workspaces
from spec_kitty_tracker.resource_discovery import discover_resources
# Canonical
from spec_kitty_tracker import discover_workspaces, discover_resources
The shim modules will not be removed in a backward-incompatible way without a separate migration mission.
Local/Native and Test Connectors
For connectors that do not use SaaS-hosted transport, construct them directly.
Local/Native (Beads)
from spec_kitty_tracker import BeadsConnector, BeadsConnectorConfig
config = BeadsConnectorConfig(workspace="my-project", cwd="/path/to/beads")
connector = BeadsConnector(config)
Test/Reference (InMemory)
from spec_kitty_tracker import InMemoryConnector
connector = InMemoryConnector(name="test", workspace="test-ws")
Migration/Advanced (direct SaaS-backed, non-product path)
# For test, migration, or advanced SDK use cases only.
# The Spec Kitty CLI/SaaS product path should use create_hosted_connector().
from spec_kitty_tracker import LinearConnector, LinearConnectorConfig
config = LinearConnectorConfig(api_key="test-key", team_id="TEAM-1")
connector = LinearConnector(config)
Design Notes
- The core contract is intentionally tracker-agnostic.
OwnershipPolicymakes source-of-truth behavior explicit and auditable.SyncEnginesupports pull, push, and bidirectional sync with conflict records.- Capability flags gate optional features (e.g., hierarchy, dependencies, webhooks).
- Mission updates are idempotent and persist decision references back to source issues.
Docs
Project details
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 spec_kitty_tracker-0.4.2.tar.gz.
File metadata
- Download URL: spec_kitty_tracker-0.4.2.tar.gz
- Upload date:
- Size: 81.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b9bb9149191096d62325410916d6edec6c0623e8538e9bb43821943f0391c40
|
|
| MD5 |
174c9f8fcef30fc0653397774ba7c0f8
|
|
| BLAKE2b-256 |
9346bef0812a23993f50b9f496d6ffb185f7967ebf0c4b6dc51e13f6d2349468
|
Provenance
The following attestation bundles were made for spec_kitty_tracker-0.4.2.tar.gz:
Publisher:
publish-pypi.yml on Priivacy-ai/spec-kitty-tracker
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spec_kitty_tracker-0.4.2.tar.gz -
Subject digest:
1b9bb9149191096d62325410916d6edec6c0623e8538e9bb43821943f0391c40 - Sigstore transparency entry: 1295055259
- Sigstore integration time:
-
Permalink:
Priivacy-ai/spec-kitty-tracker@40cf5e40d144e7d044780a259d3882a2348d5723 -
Branch / Tag:
refs/tags/v0.4.2 - Owner: https://github.com/Priivacy-ai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@40cf5e40d144e7d044780a259d3882a2348d5723 -
Trigger Event:
push
-
Statement type:
File details
Details for the file spec_kitty_tracker-0.4.2-py3-none-any.whl.
File metadata
- Download URL: spec_kitty_tracker-0.4.2-py3-none-any.whl
- Upload date:
- Size: 66.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2f985380ca3e7f56c83769051e17e9ac7a56e3f8a6b9eeffeeb8dfad04a3638c
|
|
| MD5 |
d961143389cde2c9e608b87deb8fa866
|
|
| BLAKE2b-256 |
2cc99c8358fe802e266d30ad873eacbe6a832f15f78abf538d5f44f35373fdea
|
Provenance
The following attestation bundles were made for spec_kitty_tracker-0.4.2-py3-none-any.whl:
Publisher:
publish-pypi.yml on Priivacy-ai/spec-kitty-tracker
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spec_kitty_tracker-0.4.2-py3-none-any.whl -
Subject digest:
2f985380ca3e7f56c83769051e17e9ac7a56e3f8a6b9eeffeeb8dfad04a3638c - Sigstore transparency entry: 1295055392
- Sigstore integration time:
-
Permalink:
Priivacy-ai/spec-kitty-tracker@40cf5e40d144e7d044780a259d3882a2348d5723 -
Branch / Tag:
refs/tags/v0.4.2 - Owner: https://github.com/Priivacy-ai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@40cf5e40d144e7d044780a259d3882a2348d5723 -
Trigger Event:
push
-
Statement type: