akif/arclet-boards
Arclet Boards — private Kanban workspaces with AppID, DataK3, shared web and MCP actions.
A remix template · 1 remixes · Remix akif/arclet-boards
app/application/contracts.py
"""One validated command contract shared by the HTTP and MCP doors."""
from typing import Literal
from pydantic import BaseModel, ConfigDict, Field
class Input(BaseModel):
model_config = ConfigDict(extra="forbid", strict=True)
class Empty(Input):
pass
class WorkspaceIn(Input):
title: str
class WorkspaceId(Input):
workspace_id: str
class BoardIn(Input):
title: str
workspace_id: str
description: str = ""
color: str = "indigo"
class BoardId(Input):
board_id: str
class BoardEdit(BoardId):
title: str
description: str = ""
color: str = "indigo"
version: int = Field(ge=1)
class ListIn(BoardId):
title: str
is_done: bool = False
class ListEdit(Input):
list_id: str
title: str
is_done: bool
version: int = Field(ge=1)
class ListOrder(BoardId):
list_ids: list[str] = Field(max_length=100)
version: int = Field(ge=1)
class CardIn(BoardId):
list_id: str
title: str
description: str = ""
assignee: str | None = None
due_date: str | None = None
class CardId(Input):
card_id: str
class Label(Input):
name: str
color: str
class CardEdit(CardId):
title: str
description: str
assignee: str | None
due_date: str | None
labels: list[Label] = Field(max_length=12)
version: int = Field(ge=1)
class CardMove(CardId):
list_id: str
index: int = Field(ge=0, le=10000)
version: int = Field(ge=1)
board_version: int = Field(ge=1)
class CardAssign(CardId):
assignee: str | None
version: int = Field(ge=1)
class CardDue(CardId):
due_date: str | None
version: int = Field(ge=1)
class MemberIn(BoardId):
email: str
role: Literal["member", "viewer"] = "member"
class MemberRemove(BoardId):
email: str
class WorkspaceMember(WorkspaceId):
email: str
role: Literal["member", "viewer"] = "member"
class ChecklistIn(CardId):
title: str
version: int = Field(ge=1)
class ChecklistEdit(Input):
item_id: str
completed: bool
version: int = Field(ge=1)
class DependencyIn(CardId):
depends_on_id: str
version: int = Field(ge=1)
class ApplyChecklist(CardId):
items: list[str] = Field(min_length=1, max_length=8)
version: int = Field(ge=1)
class IndexBoard(BoardId):
version: int = Field(ge=1)
READS = {
"list_workspaces": Empty, "get_workspace": WorkspaceId,
"list_boards": Empty, "get_board": BoardId, "get_card": CardId,
"list_my_cards": Empty, "list_overdue": Empty, "get_card_activity": CardId,
"list_members": BoardId,
"get_blocking_chain": CardId, "suggest_checklist": CardId,
"daily_summary": BoardId, "find_similar_cards": CardId,
}
WRITES = {
"create_workspace": WorkspaceIn, "invite_workspace_member": WorkspaceMember,
"create_board": BoardIn, "update_board": BoardEdit,
"create_list": ListIn, "update_list": ListEdit, "reorder_lists": ListOrder,
"add_card": CardIn, "update_card": CardEdit, "move_card": CardMove,
"assign_card": CardAssign, "set_due_date": CardDue,
"invite_member": MemberIn, "change_member_role": MemberIn,
"remove_member": MemberRemove, "add_checklist_item": ChecklistIn,
"complete_checklist_item": ChecklistEdit,
"add_dependency": DependencyIn, "remove_dependency": DependencyIn,
"apply_checklist": ApplyChecklist, "refresh_semantic_index": IndexBoard,
}
AI_ACTIONS = {"suggest_checklist", "daily_summary", "refresh_semantic_index"}