Add hub-core package, docs, and State Hub integration scaffold

Extract the first reusable slice (models, schemas, routers, MCP, migrations)
from state-hub with INTENT/SCOPE, agent instructions, workplan, and aligned
inter_hub capability registry index.
This commit is contained in:
2026-06-16 02:39:36 +02:00
parent d3ee203a3a
commit 986ac4d40b
52 changed files with 4085 additions and 3 deletions

View File

@@ -0,0 +1,74 @@
from hub_core.schemas.agent_message import MessageCreate, MessageRead, MessageReply
from hub_core.schemas.capability import (
CapabilityRequestAccept,
CapabilityRequestCreate,
CapabilityRequestDispute,
CapabilityRequestPatch,
CapabilityRequestRead,
CapabilityRequestStatusPatch,
CatalogCreate,
CatalogPatch,
CatalogRead,
)
from hub_core.schemas.doi import DoICriterion, DoIReport, DoISummaryEntry
from hub_core.schemas.domain import DomainCreate, DomainDetail, DomainRead, DomainRename, DomainUpdate
from hub_core.schemas.managed_repo import RepoCreate, RepoPathRegister, RepoRead, RepoUpdate
from hub_core.schemas.policy import PolicyRead, PolicyUpdate
from hub_core.schemas.progress_event import ProgressEventCreate, ProgressEventRead
from hub_core.schemas.tpsc import (
AuthType,
GDPRMaturity,
GDPR_WARNING_LEVELS,
PricingModel,
TPSCCatalogCreate,
TPSCCatalogRead,
TPSCEntryCreate,
TPSCEntryRead,
TPSCGDPRReport,
TPSCGDPRWarning,
TPSCIngestRequest,
TPSCSnapshotRead,
)
__all__ = [
"CapabilityRequestAccept",
"CapabilityRequestCreate",
"CapabilityRequestDispute",
"CapabilityRequestPatch",
"CapabilityRequestRead",
"CapabilityRequestStatusPatch",
"CatalogCreate",
"CatalogPatch",
"CatalogRead",
"DoICriterion",
"DoIReport",
"DoISummaryEntry",
"DomainCreate",
"DomainDetail",
"DomainRead",
"DomainRename",
"DomainUpdate",
"AuthType",
"GDPRMaturity",
"GDPR_WARNING_LEVELS",
"MessageCreate",
"MessageRead",
"MessageReply",
"PolicyRead",
"PolicyUpdate",
"PricingModel",
"ProgressEventCreate",
"ProgressEventRead",
"RepoCreate",
"RepoPathRegister",
"RepoRead",
"RepoUpdate",
"TPSCCatalogCreate",
"TPSCCatalogRead",
"TPSCEntryCreate",
"TPSCEntryRead",
"TPSCGDPRReport",
"TPSCGDPRWarning",
"TPSCIngestRequest",
"TPSCSnapshotRead",
]

View File

@@ -0,0 +1,31 @@
import uuid
from datetime import datetime
from pydantic import BaseModel, ConfigDict
class MessageCreate(BaseModel):
from_agent: str
to_agent: str
subject: str
body: str
thread_id: uuid.UUID | None = None
class MessageReply(BaseModel):
from_agent: str
body: str
class MessageRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
from_agent: str
to_agent: str
subject: str
body: str
thread_id: uuid.UUID | None = None
read_at: datetime | None = None
archived_at: datetime | None = None
created_at: datetime

View File

@@ -0,0 +1,99 @@
import uuid
from datetime import datetime
from typing import Any
from pydantic import BaseModel, ConfigDict, Field
class CatalogCreate(BaseModel):
domain: str
capability_type: str
title: str
description: str | None = None
keywords: list[str] = Field(default_factory=list)
repo_slug: str | None = None
class CatalogPatch(BaseModel):
repo_slug: str | None = None
description: str | None = None
keywords: list[str] | None = None
status: str | None = None
class CatalogRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
domain_slug: str
repo_id: uuid.UUID | None = None
repo_slug: str | None = None
capability_type: str
title: str
description: str | None = None
keywords: list[str] = Field(default_factory=list)
status: str
created_at: datetime
updated_at: datetime
class CapabilityRequestCreate(BaseModel):
title: str
description: str | None = None
capability_type: str
priority: str = "medium"
requesting_domain: str
requesting_agent: str
request_context: dict[str, Any] | None = None
catalog_entry_id: uuid.UUID | None = None
class CapabilityRequestAccept(BaseModel):
fulfilling_agent: str
fulfillment_context: dict[str, Any] | None = None
class CapabilityRequestStatusPatch(BaseModel):
status: str
note: str | None = None
class CapabilityRequestPatch(BaseModel):
catalog_entry_id: uuid.UUID | None = None
priority: str | None = None
request_context: dict[str, Any] | None = None
fulfillment_context: dict[str, Any] | None = None
class CapabilityRequestDispute(BaseModel):
reason: str
disputed_by: str
suggested_domain: str | None = None
class CapabilityRequestRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
title: str
description: str | None = None
capability_type: str
priority: str
status: str
requesting_domain_slug: str
requesting_agent: str
request_context: dict[str, Any] | None = None
fulfilling_domain_slug: str | None = None
fulfilling_agent: str | None = None
fulfillment_context: dict[str, Any] | None = None
catalog_entry_id: uuid.UUID | None = None
resolution_note: str | None = None
routing_note: str | None = None
dispute_reason: str | None = None
disputed_by: str | None = None
dispute_suggested_domain: str | None = None
disputed_at: datetime | None = None
accepted_at: datetime | None = None
completed_at: datetime | None = None
created_at: datetime
updated_at: datetime

29
hub_core/schemas/doi.py Normal file
View File

@@ -0,0 +1,29 @@
from pydantic import BaseModel
class DoICriterion(BaseModel):
id: str
label: str
tier: str
status: str
detail: str = ""
class DoIReport(BaseModel):
repo_slug: str
tier: str
core_pass: bool
standard_pass: bool
full_pass: bool
criteria: list[DoICriterion] = []
checked_at: str
class DoISummaryEntry(BaseModel):
repo_slug: str
domain_slug: str | None
tier: str
core_pass: bool
standard_pass: bool
full_pass: bool
checked_at: str

View File

@@ -0,0 +1,49 @@
import uuid
from datetime import datetime
from pydantic import BaseModel, ConfigDict, Field
class DomainCreate(BaseModel):
slug: str
name: str
description: str | None = None
class DomainUpdate(BaseModel):
name: str | None = None
description: str | None = None
status: str | None = None
class DomainRename(BaseModel):
new_slug: str
new_name: str
class RepoStub(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
slug: str
name: str
local_path: str | None = None
remote_url: str | None = None
status: str
class DomainRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
slug: str
name: str
description: str | None = None
status: str
created_at: datetime
updated_at: datetime
class DomainDetail(DomainRead):
repos: list[RepoStub] = Field(default_factory=list)
extension_counts: dict[str, int] = Field(default_factory=dict)

View File

@@ -0,0 +1,48 @@
import uuid
from datetime import datetime
from pydantic import BaseModel, ConfigDict, Field
class RepoCreate(BaseModel):
domain_slug: str
slug: str
name: str
local_path: str | None = None
host_paths: dict = Field(default_factory=dict)
remote_url: str | None = None
git_fingerprint: str | None = None
description: str | None = None
class RepoUpdate(BaseModel):
name: str | None = None
local_path: str | None = None
host_paths: dict | None = None
remote_url: str | None = None
git_fingerprint: str | None = None
description: str | None = None
status: str | None = None
class RepoPathRegister(BaseModel):
host: str
path: str
class RepoRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
domain_id: uuid.UUID
domain_slug: str
slug: str
name: str
local_path: str | None = None
host_paths: dict = Field(default_factory=dict)
remote_url: str | None = None
git_fingerprint: str | None = None
description: str | None = None
status: str
created_at: datetime
updated_at: datetime

View File

@@ -0,0 +1,10 @@
from pydantic import BaseModel
class PolicyRead(BaseModel):
name: str
content: str
class PolicyUpdate(BaseModel):
content: str

View File

@@ -0,0 +1,27 @@
import uuid
from datetime import datetime
from typing import Any
from pydantic import BaseModel, ConfigDict
class ProgressEventCreate(BaseModel):
event_type: str
summary: str
detail: dict[str, Any] | None = None
subject_refs: dict[str, Any] | None = None
author: str | None = None
session_id: str | None = None
class ProgressEventRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
event_type: str
summary: str
detail: dict[str, Any] | None = None
subject_refs: dict[str, Any] | None = None
author: str | None = None
session_id: str | None = None
created_at: datetime

116
hub_core/schemas/tpsc.py Normal file
View File

@@ -0,0 +1,116 @@
import uuid
from datetime import datetime
from typing import Literal
from pydantic import BaseModel, ConfigDict, Field, computed_field
GDPRMaturity = Literal[
"unknown",
"non_compliant",
"initial",
"developing",
"defined",
"managed",
"certified",
]
GDPR_WARNING_LEVELS = {"unknown", "non_compliant", "initial"}
PricingModel = Literal["free", "paid", "freemium", "usage_based", "unknown"]
AuthType = Literal["api_key", "oauth", "cli", "none", "unknown"]
class TPSCCatalogCreate(BaseModel):
slug: str
name: str
provider: str | None = None
category: str | None = None
website_url: str | None = None
pricing_model: PricingModel = "unknown"
gdpr_maturity: GDPRMaturity = "unknown"
gdpr_notes: str | None = None
dpa_available: bool = False
tos_url: str | None = None
privacy_policy_url: str | None = None
data_processing_regions: list[str] | None = None
data_retention_notes: str | None = None
status: str = "active"
class TPSCCatalogRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
slug: str
name: str
provider: str | None
category: str | None
website_url: str | None
pricing_model: str
gdpr_maturity: str
gdpr_notes: str | None
dpa_available: bool
tos_url: str | None
privacy_policy_url: str | None
data_processing_regions: list[str] | None
data_retention_notes: str | None
status: str
created_at: datetime
updated_at: datetime
@computed_field
@property
def gdpr_warning(self) -> bool:
return self.gdpr_maturity in GDPR_WARNING_LEVELS
class TPSCEntryCreate(BaseModel):
service_slug: str
purpose: str | None = None
auth_type: str | None = None
endpoint_override: str | None = None
notes: str | None = None
class TPSCEntryRead(TPSCEntryCreate):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
snapshot_id: uuid.UUID
catalog_id: uuid.UUID | None = None
gdpr_maturity: str | None = None
gdpr_warning: bool = False
pricing_model: str | None = None
class TPSCIngestRequest(BaseModel):
repo_slug: str
source_file: str = "tpsc.yaml"
entries: list[TPSCEntryCreate]
class TPSCSnapshotRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
repo_id: uuid.UUID | None = None
snapshot_at: datetime
source_file: str | None = None
entry_count: int
entries: list[TPSCEntryRead] = Field(default_factory=list)
class TPSCGDPRWarning(BaseModel):
repo_slug: str | None
service_slug: str
gdpr_maturity: str
purpose: str | None
pricing_model: str | None
class TPSCGDPRReport(BaseModel):
generated_at: datetime
total_services: int
warning_count: int
warnings: list[TPSCGDPRWarning]
by_maturity: dict[str, int]