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
Metadata
Release files for spec-kitty-tracker 0.5.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| spec_kitty_tracker-0.5.2.tar.gz | 134.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| spec_kitty_tracker-0.5.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 219.0 kB
Release files / spec_kitty_tracker-0.5.2.tar.gz
| Download URL | spec_kitty_tracker-0.5.2.tar.gz |
|---|---|
| Size | 134.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
192f56a9247f0e4ea90002a6d9ef25f5c47efa54989c33766c1aca8966eaa1f8
|
|
BLAKE2b-256 checksum How to use checksums |
cb8a60677d184ffc0817c818e369c7a37a62063f5372d3370ad25208a666822e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 1, 2026.
Transparency logRelease files / spec_kitty_tracker-0.5.2-py3-none-any.whl
| Download URL | spec_kitty_tracker-0.5.2-py3-none-any.whl |
|---|---|
| Size | 85.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f614967c214cc29b5664572d7bbbee44706ceff22b8106cfa462f3bb84fcc39f
|
|
BLAKE2b-256 checksum How to use checksums |
5bac69f37ae99cacb50cb4a6e76386fb83704cc3657f2a949630bf626a96dd1d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 1, 2026.
Transparency log