commits
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add PullInfo, PullSource, PullTarget, ListPullsResult types
- implement list_repo_pulls in _tangled module
- note: only shows PRs created by authenticated user (atproto limitation)
- test: 7 tools now exposed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- fix _extract_error_message to handle e.response.content.message structure
- add tests for error message extraction
- tested against atproto_client exception hierarchy
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add _extract_error_message() to produce concise error output
- skip issues with missing issueId in list_repo_issues
- truncate verbose exception details (HTTP headers, etc.)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- rename `issue_id` → `id` for consistency across all types
- exclude redundant `repo` field from serialized output
(still available internally for URL computation)
- add test verifying repo exclusion from serialization
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- update schema from 2025-09-29 to 2025-10-17
- update version to 0.0.11 to match git tag
- fixes MCP registry publish failure
validate labels before creating issue
fixes #13
- move _validate_labels call before issue creation
- prevents creating orphaned issues when labels are invalid
- fail fast with clear error message listing available labels
- cursor is an implementation detail, not useful for LLM workflows
- LLMs don't naturally paginate - they want all results or a filtered subset
- keep cursor parameter in internal functions for future use
- remove from:
- list_repo_branches tool signature
- list_repo_issues tool signature
- ListBranchesResult response type
- ListIssuesResult response type
- update tests to not check cursor field
- move design-pulls.md to sandbox/ (exploratory, not production-ready)
- add critical warning: PRs can't work via atproto records
- appview doesn't subscribe to sh.tangled.repo.pull in jetstream
- no firehose ingester for pulls (only issues have ingestIssue)
- web UI creates DB entries directly, atproto record is decorative
- improve release.md wording (current repo vs current release)
- add tree reminder to CLAUDE.md
PR support would require tangled-core changes (adding firehose consumer).
The design is architecturally sound but incompatible with current implementation.
- document all gh pr commands and map to tangled MCP tools
- 8 tools: create, update, list, get, close, reopen, merge, ready
- preserve gh parameter names and semantics where possible
- key differences: user-provided patches, logical-only merges
- draft state as custom status value
- label reuse from issues (subject-based ops)
- default limit 30 (matching gh)
also update CLAUDE.md:
- use jq for JSON parsing (not python pipes)
- never use sleep (poll with tools instead)
## critical fixes
### 1. fix pydantic field warning
- remove invalid `Field(default=None)` from settings.py
- change to `tangled_pds_url: str | None = None`
### 2. add loud label validation
- new `_validate_labels()` helper checks labels against repo's subscribed definitions
- raises `ValueError` with available labels list when invalid labels provided
- prevents silent failures when creating/updating issues
### 3. include labels in list_repo_issues
- add `labels: list[str]` field to `IssueInfo` model
- fetch and correlate label ops with issues
- return label names (not URIs) for better UX
### 4. add list_repo_labels tool
- new tool to query available labels for a repository
- extracts label names from repo's subscribed label definitions
- helps users discover which labels they can use
## changes
- src/tangled_mcp/settings.py: fix pydantic warning
- src/tangled_mcp/_tangled/_issues.py: add validation, label fetching, new tool
- src/tangled_mcp/types/_issues.py: add labels field to IssueInfo
- src/tangled_mcp/server.py: expose list_repo_labels tool
- src/tangled_mcp/_tangled/__init__.py: export list_repo_labels
- tests/test_server.py: update tool count (5 -> 6)
- README.md: document new tool
all 17 tests passing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
## types architecture
- refactor types.py → types/ directory structure
- _common.py: RepoIdentifier validation with Annotated types
- _branches.py: branch types + ListBranchesResult.from_api_response()
- _issues.py: issue types + ListIssuesResult.from_api_response()
- __init__.py: public API
- move parsing logic into types via class method constructors
- parsing logic out of tool functions (DRY, separation of concerns)
## issue operations improvements
- return clickable URLs instead of AT Protocol URIs/CIDs
- CreateIssueResult/UpdateIssueResult: {url, issue_id}
- DeleteIssueResult: {issue_id}
- URL generation via @computed_field in types
- RepoIdentifier validator strips @ prefix, normalizes format
- all operations return proper Pydantic models (no dict[str, Any])
## better auth error messages
- _get_authenticated_client() now provides actionable errors
- tells users to verify TANGLED_HANDLE and TANGLED_PASSWORD
## documentation
- wrap MCP client installation in <details> for cleaner README
- add NEXT_STEPS.md documenting critical issues found:
- silent label validation failures (labels must fail loudly)
- missing label data in list_repo_issues
- pydantic field warning
## testing
- add test_types.py with 9 tests covering public API
- validates: RepoIdentifier normalization, URL generation, API parsing
- all 17 tests passing
no breaking changes to public API, all existing functionality preserved
- add usage section with client setup for claude code, cursor, codex cli, and generic clients
- improve authentication error messages in _client.py with actionable guidance
- simplify justfile: remove opinionated push/release commands
- document release process in docs/publishing.md
- bump server.json to 0.0.9
- add labels parameter to create_repo_issue
- implement update_repo_issue (update title, body, and/or labels)
- implement delete_repo_issue
- refactor code into _client.py (auth, repo, branches) and _issues.py
- fix variable collision bug (walrus operator shadowing function parameter)
- update README with all tools
- add PullInfo, PullSource, PullTarget, ListPullsResult types
- implement list_repo_pulls in _tangled module
- note: only shows PRs created by authenticated user (atproto limitation)
- test: 7 tools now exposed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- rename `issue_id` → `id` for consistency across all types
- exclude redundant `repo` field from serialized output
(still available internally for URL computation)
- add test verifying repo exclusion from serialization
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
fixes #13
- move _validate_labels call before issue creation
- prevents creating orphaned issues when labels are invalid
- fail fast with clear error message listing available labels
- cursor is an implementation detail, not useful for LLM workflows
- LLMs don't naturally paginate - they want all results or a filtered subset
- keep cursor parameter in internal functions for future use
- remove from:
- list_repo_branches tool signature
- list_repo_issues tool signature
- ListBranchesResult response type
- ListIssuesResult response type
- update tests to not check cursor field
- move design-pulls.md to sandbox/ (exploratory, not production-ready)
- add critical warning: PRs can't work via atproto records
- appview doesn't subscribe to sh.tangled.repo.pull in jetstream
- no firehose ingester for pulls (only issues have ingestIssue)
- web UI creates DB entries directly, atproto record is decorative
- improve release.md wording (current repo vs current release)
- add tree reminder to CLAUDE.md
PR support would require tangled-core changes (adding firehose consumer).
The design is architecturally sound but incompatible with current implementation.
- document all gh pr commands and map to tangled MCP tools
- 8 tools: create, update, list, get, close, reopen, merge, ready
- preserve gh parameter names and semantics where possible
- key differences: user-provided patches, logical-only merges
- draft state as custom status value
- label reuse from issues (subject-based ops)
- default limit 30 (matching gh)
also update CLAUDE.md:
- use jq for JSON parsing (not python pipes)
- never use sleep (poll with tools instead)
## critical fixes
### 1. fix pydantic field warning
- remove invalid `Field(default=None)` from settings.py
- change to `tangled_pds_url: str | None = None`
### 2. add loud label validation
- new `_validate_labels()` helper checks labels against repo's subscribed definitions
- raises `ValueError` with available labels list when invalid labels provided
- prevents silent failures when creating/updating issues
### 3. include labels in list_repo_issues
- add `labels: list[str]` field to `IssueInfo` model
- fetch and correlate label ops with issues
- return label names (not URIs) for better UX
### 4. add list_repo_labels tool
- new tool to query available labels for a repository
- extracts label names from repo's subscribed label definitions
- helps users discover which labels they can use
## changes
- src/tangled_mcp/settings.py: fix pydantic warning
- src/tangled_mcp/_tangled/_issues.py: add validation, label fetching, new tool
- src/tangled_mcp/types/_issues.py: add labels field to IssueInfo
- src/tangled_mcp/server.py: expose list_repo_labels tool
- src/tangled_mcp/_tangled/__init__.py: export list_repo_labels
- tests/test_server.py: update tool count (5 -> 6)
- README.md: document new tool
all 17 tests passing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
## types architecture
- refactor types.py → types/ directory structure
- _common.py: RepoIdentifier validation with Annotated types
- _branches.py: branch types + ListBranchesResult.from_api_response()
- _issues.py: issue types + ListIssuesResult.from_api_response()
- __init__.py: public API
- move parsing logic into types via class method constructors
- parsing logic out of tool functions (DRY, separation of concerns)
## issue operations improvements
- return clickable URLs instead of AT Protocol URIs/CIDs
- CreateIssueResult/UpdateIssueResult: {url, issue_id}
- DeleteIssueResult: {issue_id}
- URL generation via @computed_field in types
- RepoIdentifier validator strips @ prefix, normalizes format
- all operations return proper Pydantic models (no dict[str, Any])
## better auth error messages
- _get_authenticated_client() now provides actionable errors
- tells users to verify TANGLED_HANDLE and TANGLED_PASSWORD
## documentation
- wrap MCP client installation in <details> for cleaner README
- add NEXT_STEPS.md documenting critical issues found:
- silent label validation failures (labels must fail loudly)
- missing label data in list_repo_issues
- pydantic field warning
## testing
- add test_types.py with 9 tests covering public API
- validates: RepoIdentifier normalization, URL generation, API parsing
- all 17 tests passing
no breaking changes to public API, all existing functionality preserved
- add usage section with client setup for claude code, cursor, codex cli, and generic clients
- improve authentication error messages in _client.py with actionable guidance
- simplify justfile: remove opinionated push/release commands
- document release process in docs/publishing.md
- bump server.json to 0.0.9
- add labels parameter to create_repo_issue
- implement update_repo_issue (update title, body, and/or labels)
- implement delete_repo_issue
- refactor code into _client.py (auth, repo, branches) and _issues.py
- fix variable collision bug (walrus operator shadowing function parameter)
- update README with all tools