margo-tooling 0.5.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. margo_tooling-0.5.1/.github/workflows/ci.yml +37 -0
  2. margo_tooling-0.5.1/.github/workflows/docs.yml +44 -0
  3. margo_tooling-0.5.1/.github/workflows/publish-pypi.yml +36 -0
  4. margo_tooling-0.5.1/.github/workflows/release-check.yml +45 -0
  5. margo_tooling-0.5.1/.github/workflows/release.yml +105 -0
  6. margo_tooling-0.5.1/.gitignore +44 -0
  7. margo_tooling-0.5.1/.kiro/agents/docs-writer.json +63 -0
  8. margo_tooling-0.5.1/.kiro/agents/planner.json +85 -0
  9. margo_tooling-0.5.1/.kiro/agents/python-dev.json +60 -0
  10. margo_tooling-0.5.1/.kiro/skills/code-quality-enhancement/SKILL.md +88 -0
  11. margo_tooling-0.5.1/.kiro/skills/fix-todos/SKILL.md +51 -0
  12. margo_tooling-0.5.1/.kiro/sprints/sprint-5.md +408 -0
  13. margo_tooling-0.5.1/.kiro/sprints/sprint-6.md +342 -0
  14. margo_tooling-0.5.1/.kiro/steering/code-conventions.md +66 -0
  15. margo_tooling-0.5.1/.kiro/steering/documentation.md +52 -0
  16. margo_tooling-0.5.1/.kiro/steering/oci-media-types.md +48 -0
  17. margo_tooling-0.5.1/AGENTS.md +38 -0
  18. margo_tooling-0.5.1/CONTRIBUTING.md +98 -0
  19. margo_tooling-0.5.1/Containerfile +22 -0
  20. margo_tooling-0.5.1/FEATURES.md +691 -0
  21. margo_tooling-0.5.1/LICENSE +201 -0
  22. margo_tooling-0.5.1/Makefile +24 -0
  23. margo_tooling-0.5.1/PKG-INFO +13 -0
  24. margo_tooling-0.5.1/ROADMAP.md +95 -0
  25. margo_tooling-0.5.1/TESTING.md +64 -0
  26. margo_tooling-0.5.1/cliff.toml +51 -0
  27. margo_tooling-0.5.1/docs/examples/basic-quadlet.md +92 -0
  28. margo_tooling-0.5.1/docs/examples/full.md +304 -0
  29. margo_tooling-0.5.1/docs/examples/image-search-replace.md +145 -0
  30. margo_tooling-0.5.1/docs/examples/minimal.md +70 -0
  31. margo_tooling-0.5.1/docs/index.md +27 -0
  32. margo_tooling-0.5.1/docs/margo-yaml.md +217 -0
  33. margo_tooling-0.5.1/docs/stylesheets/extra.css +5 -0
  34. margo_tooling-0.5.1/mkdocs.yml +38 -0
  35. margo_tooling-0.5.1/pyproject.toml +103 -0
  36. margo_tooling-0.5.1/src/margot/__init__.py +0 -0
  37. margo_tooling-0.5.1/src/margot/commands/__init__.py +1 -0
  38. margo_tooling-0.5.1/src/margot/commands/auth.py +117 -0
  39. margo_tooling-0.5.1/src/margot/commands/build.py +88 -0
  40. margo_tooling-0.5.1/src/margot/commands/fetch.py +22 -0
  41. margo_tooling-0.5.1/src/margot/commands/global_options.py +29 -0
  42. margo_tooling-0.5.1/src/margot/commands/pull.py +56 -0
  43. margo_tooling-0.5.1/src/margot/commands/push.py +91 -0
  44. margo_tooling-0.5.1/src/margot/commands/version.py +11 -0
  45. margo_tooling-0.5.1/src/margot/config.py +75 -0
  46. margo_tooling-0.5.1/src/margot/console.py +148 -0
  47. margo_tooling-0.5.1/src/margot/domain/__init__.py +0 -0
  48. margo_tooling-0.5.1/src/margot/domain/auth.py +81 -0
  49. margo_tooling-0.5.1/src/margot/domain/layers.py +102 -0
  50. margo_tooling-0.5.1/src/margot/domain/metadata.py +235 -0
  51. margo_tooling-0.5.1/src/margot/domain/models.py +49 -0
  52. margo_tooling-0.5.1/src/margot/domain/tags.py +53 -0
  53. margo_tooling-0.5.1/src/margot/domain/uri.py +77 -0
  54. margo_tooling-0.5.1/src/margot/infra/__init__.py +1 -0
  55. margo_tooling-0.5.1/src/margot/infra/credentials.py +196 -0
  56. margo_tooling-0.5.1/src/margot/infra/filesystem.py +97 -0
  57. margo_tooling-0.5.1/src/margot/infra/oci.py +350 -0
  58. margo_tooling-0.5.1/src/margot/main.py +33 -0
  59. margo_tooling-0.5.1/src/margot/services/__init__.py +1 -0
  60. margo_tooling-0.5.1/src/margot/services/auth.py +93 -0
  61. margo_tooling-0.5.1/src/margot/services/build.py +250 -0
  62. margo_tooling-0.5.1/src/margot/services/fetch.py +33 -0
  63. margo_tooling-0.5.1/src/margot/services/pull.py +171 -0
  64. margo_tooling-0.5.1/src/margot/services/push.py +372 -0
  65. margo_tooling-0.5.1/tests/__init__.py +0 -0
  66. margo_tooling-0.5.1/tests/conftest.py +73 -0
  67. margo_tooling-0.5.1/tests/e2e/__init__.py +1 -0
  68. margo_tooling-0.5.1/tests/e2e/test_auth_cli.py +285 -0
  69. margo_tooling-0.5.1/tests/e2e/test_build_cli.py +369 -0
  70. margo_tooling-0.5.1/tests/e2e/test_fetch_cli.py +162 -0
  71. margo_tooling-0.5.1/tests/e2e/test_pull_cli.py +451 -0
  72. margo_tooling-0.5.1/tests/e2e/test_push_cli.py +205 -0
  73. margo_tooling-0.5.1/tests/integration/__init__.py +1 -0
  74. margo_tooling-0.5.1/tests/integration/test_auth_service.py +249 -0
  75. margo_tooling-0.5.1/tests/integration/test_build.py +893 -0
  76. margo_tooling-0.5.1/tests/integration/test_fetch_service.py +174 -0
  77. margo_tooling-0.5.1/tests/integration/test_pull_service.py +651 -0
  78. margo_tooling-0.5.1/tests/integration/test_push_service.py +818 -0
  79. margo_tooling-0.5.1/tests/test_smoke.py +24 -0
  80. margo_tooling-0.5.1/tests/unit/__init__.py +1 -0
  81. margo_tooling-0.5.1/tests/unit/test_config.py +205 -0
  82. margo_tooling-0.5.1/tests/unit/test_console.py +396 -0
  83. margo_tooling-0.5.1/tests/unit/test_credentials.py +400 -0
  84. margo_tooling-0.5.1/tests/unit/test_domain_auth.py +135 -0
  85. margo_tooling-0.5.1/tests/unit/test_domain_layers.py +282 -0
  86. margo_tooling-0.5.1/tests/unit/test_domain_models.py +103 -0
  87. margo_tooling-0.5.1/tests/unit/test_domain_uri.py +127 -0
  88. margo_tooling-0.5.1/tests/unit/test_filesystem.py +409 -0
  89. margo_tooling-0.5.1/tests/unit/test_global_options.py +49 -0
  90. margo_tooling-0.5.1/tests/unit/test_infra_oci.py +234 -0
  91. margo_tooling-0.5.1/tests/unit/test_infra_oci_push.py +364 -0
  92. margo_tooling-0.5.1/tests/unit/test_metadata.py +759 -0
  93. margo_tooling-0.5.1/tests/unit/test_tags.py +90 -0
  94. margo_tooling-0.5.1/uv.lock +965 -0
@@ -0,0 +1,37 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ jobs:
9
+ check:
10
+ name: Lint
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - uses: astral-sh/setup-uv@v6
16
+ with:
17
+ enable-cache: true
18
+
19
+ - name: lint
20
+ run: make lint
21
+
22
+ test:
23
+ name: Test (Python ${{ matrix.python-version }})
24
+ runs-on: ubuntu-latest
25
+ strategy:
26
+ matrix:
27
+ python-version: ["3.12", "3.13", "3.14"]
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+
31
+ - uses: astral-sh/setup-uv@v6
32
+ with:
33
+ enable-cache: true
34
+ python-version: ${{ matrix.python-version }}
35
+
36
+ - name: pytest
37
+ run: make test
@@ -0,0 +1,44 @@
1
+ name: Docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ permissions:
8
+ contents: read
9
+ pages: write
10
+ id-token: write
11
+
12
+ concurrency:
13
+ group: pages
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ build:
18
+ name: Build
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - uses: astral-sh/setup-uv@v6
24
+ with:
25
+ enable-cache: true
26
+
27
+ - name: build docs
28
+ run: make docs-check
29
+
30
+ - uses: actions/upload-pages-artifact@v3
31
+ with:
32
+ path: site/
33
+
34
+ deploy:
35
+ name: Deploy
36
+ needs: build
37
+ runs-on: ubuntu-latest
38
+ environment:
39
+ name: github-pages
40
+ url: ${{ steps.deployment.outputs.page_url }}
41
+ steps:
42
+ - name: deploy to GitHub Pages
43
+ id: deployment
44
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,36 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+ inputs:
8
+ version:
9
+ description: "Git tag of the GitHub release to publish (e.g. 1.2.3)"
10
+ required: true
11
+ type: string
12
+
13
+ jobs:
14
+ publish:
15
+ runs-on: ubuntu-latest
16
+ environment: pypi
17
+ permissions:
18
+ id-token: write # required for PyPI trusted publishing
19
+
20
+ steps:
21
+ - name: Resolve release tag
22
+ id: tag
23
+ run: echo "version=${{ inputs.version || github.event.release.tag_name }}" >> "$GITHUB_OUTPUT"
24
+
25
+ - name: Download release artifacts
26
+ env:
27
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28
+ run: |
29
+ gh release download ${{ steps.tag.outputs.version }} \
30
+ --repo ${{ github.repository }} \
31
+ --pattern '*.whl' \
32
+ --pattern '*.tar.gz' \
33
+ --dir dist/
34
+
35
+ - name: Publish to PyPI
36
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,45 @@
1
+ name: Release Check
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+
7
+ jobs:
8
+ preview-release-version:
9
+ if: startsWith(github.head_ref, 'release/')
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - name: Extract version from branch name
14
+ id: version
15
+ run: |
16
+ VERSION=${GITHUB_HEAD_REF#release/}
17
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
18
+
19
+ - uses: astral-sh/setup-uv@v6
20
+
21
+ - name: Validate SemVer
22
+ run: uvx --from 'semver>=3.0,<4.0' pysemver check ${{ steps.version.outputs.version }}
23
+
24
+ preview-changelog:
25
+ if: startsWith(github.head_ref, 'release/')
26
+ runs-on: ubuntu-latest
27
+
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ with:
31
+ fetch-depth: 0
32
+
33
+ - name: Extract version from branch name
34
+ id: version
35
+ run: |
36
+ VERSION=${GITHUB_HEAD_REF#release/}
37
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
38
+
39
+ - uses: astral-sh/setup-uv@v6
40
+
41
+ - name: Preview release notes
42
+ run: |
43
+ echo "## Release notes preview for ${{ steps.version.outputs.version }}"
44
+ echo ""
45
+ uvx git-cliff --unreleased --strip header
@@ -0,0 +1,105 @@
1
+ name: Release
2
+
3
+ on:
4
+ pull_request:
5
+ types: [closed]
6
+ branches: [main]
7
+
8
+ jobs:
9
+ release:
10
+ if: github.event.pull_request.merged == true && startsWith(github.head_ref, 'release/')
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ contents: write
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ with:
18
+ fetch-depth: 0
19
+
20
+ - name: Extract version from branch name
21
+ id: version
22
+ run: |
23
+ VERSION=${GITHUB_HEAD_REF#release/}
24
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
25
+
26
+ - uses: astral-sh/setup-uv@v6
27
+
28
+ - name: Validate SemVer
29
+ run: uvx --from 'semver>=3.0,<4.0' pysemver check ${{ steps.version.outputs.version }}
30
+
31
+ - name: Tag the release commit
32
+ env:
33
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34
+ run: |
35
+ git config user.name "github-actions[bot]"
36
+ git config user.email "github-actions[bot]@users.noreply.github.com"
37
+ git tag ${{ steps.version.outputs.version }}
38
+ git push origin ${{ steps.version.outputs.version }}
39
+
40
+ - name: Build
41
+ run: uv build
42
+
43
+ - name: Generate changelog
44
+ run: uvx git-cliff --latest --strip header -o RELEASE_NOTES.md
45
+
46
+ - name: Upload artifacts
47
+ uses: actions/upload-artifact@v4
48
+ with:
49
+ name: build-artifacts
50
+ path: dist/
51
+ retention-days: 1
52
+
53
+ - name: Create release and upload artifacts
54
+ env:
55
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
56
+ run: |
57
+ gh release create ${{ steps.version.outputs.version }} dist/* \
58
+ --title "${{ steps.version.outputs.version }}" \
59
+ --notes-file RELEASE_NOTES.md \
60
+ --target main
61
+
62
+ container:
63
+ needs: release
64
+ if: github.event.pull_request.merged == true && startsWith(github.head_ref, 'release/')
65
+ runs-on: ubuntu-latest
66
+ permissions:
67
+ packages: write
68
+
69
+ steps:
70
+ - uses: actions/checkout@v4
71
+
72
+ - name: Extract version from branch name
73
+ id: version
74
+ run: |
75
+ VERSION=${GITHUB_HEAD_REF#release/}
76
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
77
+
78
+ - name: Compute container image tag
79
+ id: image
80
+ run: |
81
+ IMAGE_NAME=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
82
+ echo "name=$IMAGE_NAME" >> $GITHUB_OUTPUT
83
+
84
+ - name: Download artifacts
85
+ uses: actions/download-artifact@v4
86
+ with:
87
+ name: build-artifacts
88
+ path: dist/
89
+
90
+ - name: Log in to GHCR
91
+ uses: docker/login-action@v3
92
+ with:
93
+ registry: ghcr.io
94
+ username: ${{ github.actor }}
95
+ password: ${{ secrets.GITHUB_TOKEN }}
96
+
97
+ - name: Build and push container image
98
+ uses: docker/build-push-action@v6
99
+ with:
100
+ context: .
101
+ file: ./Containerfile
102
+ push: true
103
+ tags: |
104
+ ghcr.io/${{ steps.image.outputs.name }}:${{ steps.version.outputs.version }}
105
+ ghcr.io/${{ steps.image.outputs.name }}:latest
@@ -0,0 +1,44 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.pyo
5
+ *.pyd
6
+ *.egg-info/
7
+ *.egg
8
+ dist/
9
+ build/
10
+ wheels/
11
+
12
+ # Virtual environments
13
+ .venv/
14
+ venv/
15
+ env/
16
+
17
+ # uv
18
+ .uv/
19
+
20
+ # Test / coverage
21
+ .pytest_cache/
22
+ .coverage
23
+ htmlcov/
24
+ coverage.xml
25
+
26
+ # Build output
27
+ .dist/
28
+ .run/
29
+
30
+ # Git worktrees checked out inside the repo
31
+ .wk-*/
32
+
33
+ # MkDocs
34
+ site/
35
+
36
+ # Editors
37
+ .idea/
38
+ .vscode/
39
+ *.swp
40
+ *.swo
41
+
42
+ # OS
43
+ .DS_Store
44
+ Thumbs.db
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "docs-writer",
3
+ "description": "Maintains the MkDocs documentation site under docs/. Writes and edits doc content, mkdocs.yml nav, and verifies builds. Never touches Python source.",
4
+ "model": "claude-sonnet-4.6",
5
+ "prompt": "You are a technical writer maintaining the margot MkDocs site under docs/. FEATURES.md is the authoritative source of truth for behavior, architecture, commands, config, and OCI media types — docs must never contradict it. .kiro/steering/documentation.md governs doc style, audience separation, and structure; follow it exactly. When a doc page and FEATURES.md disagree, FEATURES.md wins — fix the doc, don't work around it. New user-facing behavior belongs in FEATURES.md first; you follow, you don't lead. Before writing or editing a page, read FEATURES.md and the relevant steering files. After any change under docs/ or to mkdocs.yml, run `make docs-check` (strict build, warnings as errors) and fix any failures before considering the change done. Never modify Python source, tests, or non-doc config — if a doc gap reveals a product or code issue, report it instead of fixing code. You must never edit pyproject.toml or uv.lock directly (the write tool blocks this). If a docs dependency is needed (e.g. an mkdocs plugin), add it with `uv add <package> --group docs` — never hand-edit the dependency group.",
6
+ "mcpServers": {},
7
+ "tools": [
8
+ "read",
9
+ "write",
10
+ "grep",
11
+ "glob",
12
+ "code",
13
+ "shell",
14
+ "todo"
15
+ ],
16
+ "allowedTools": [
17
+ "read",
18
+ "grep",
19
+ "glob",
20
+ "code",
21
+ "todo"
22
+ ],
23
+ "toolsSettings": {
24
+ "read": {
25
+ "allowedPaths": [
26
+ "**"
27
+ ]
28
+ },
29
+ "write": {
30
+ "allowedPaths": [
31
+ "docs/**",
32
+ "mkdocs.yml",
33
+ "*.md",
34
+ ".kiro/steering/documentation.md"
35
+ ],
36
+ "deniedPaths": [
37
+ "**/*.py",
38
+ "src/**",
39
+ "tests/**",
40
+ "pyproject.toml",
41
+ "uv.lock"
42
+ ]
43
+ },
44
+ "shell": {
45
+ "autoAllowReadonly": true,
46
+ "denyByDefault": true,
47
+ "allowedCommands": [
48
+ "make.*",
49
+ "uv.*",
50
+ "git.*"
51
+ ]
52
+ }
53
+ },
54
+ "resources": [
55
+ "file://.kiro/steering/documentation.md",
56
+ "file://.kiro/steering/oci-media-types.md",
57
+ "file://FEATURES.md",
58
+ "file://AGENTS.md"
59
+ ],
60
+ "hooks": {},
61
+ "includeMcpJson": true,
62
+ "welcomeMessage": "docs-writer ready. I maintain docs/ against FEATURES.md and documentation.md. I don't touch source code."
63
+ }
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "planner",
3
+ "description": "Sprint planner: locates TODO items, forms a plan, and delegates implementation to dev agent. Never writes code.",
4
+ "model": "claude-sonnet-5",
5
+ "prompt": "You are a senior technical planner. Your role is exclusively investigating, planning and delegation — you never write, edit, or create code files.\n\nWorkflow on every request:\n1. Define a clear plan with explicit designs, key aspect and checkable steps/aspects. Search on the web if needed.\n2. Summary plan and get final approval.\n3. Delegate the full plan to the dev agent for implementation.\n4. Report back the dev agent output and a brief summary of what was done.\n\nHard constraints:\n- You MUST NOT write, edit, or create any source or test file (no .py, .toml, .yaml, .sh, etc.).\n- You MUST NOT produce code blocks intended to be applied to files.\n- You MAY write or edit Markdown files (.md) and files under .kiro/ (specs, steering, notes, task files).\n- You MAY create planning notes, task lists, or spec files to support future work.\n- When delegating, provide dev agent with the full plan, relevant file paths and a clear definition of done (tests pass, TODO removed, changes committed).\n- After the dev agent completes, instruct it to commit all changes with a meaningful commit message (conventional commits format: `feat:`, `fix:`, `test:`, etc.). The commit is part of the definition of done — a patch is not complete until it is committed.",
6
+ "mcpServers": {},
7
+ "tools": [
8
+ "code",
9
+ "delegate",
10
+ "glob",
11
+ "grep",
12
+ "read",
13
+ "shell",
14
+ "subagent",
15
+ "todo",
16
+ "tool_search",
17
+ "web_fetch",
18
+ "web_search",
19
+ "write"
20
+ ],
21
+ "allowedTools": [
22
+ "code",
23
+ "delegate",
24
+ "glob",
25
+ "grep",
26
+ "read",
27
+ "shell",
28
+ "subagent",
29
+ "todo",
30
+ "tool_search",
31
+ "web_fetch",
32
+ "web_search",
33
+ "write"
34
+ ],
35
+ "toolsSettings": {
36
+ "read": {
37
+ "allowedPaths": [
38
+ "**"
39
+ ]
40
+ },
41
+ "write": {
42
+ "allowedPaths": [
43
+ "**/*.md",
44
+ ".kiro/**"
45
+ ],
46
+ "deniedPaths": [
47
+ "**/*.py",
48
+ "**/*.toml",
49
+ "**/*.cfg",
50
+ "**/*.ini",
51
+ "**/*.yaml",
52
+ "**/*.yml",
53
+ "**/*.json",
54
+ "**/*.txt",
55
+ "**/*.sh"
56
+ ]
57
+ },
58
+ "shell": {
59
+ "autoAllowReadonly": true,
60
+ "denyByDefault": true,
61
+ "allowedCommands": [
62
+ "find.*",
63
+ "grep.*",
64
+ "make.*"
65
+ ]
66
+ },
67
+ "subagent": {
68
+ "availableAgents": [
69
+ "python-dev"
70
+ ],
71
+ "trustedAgents": [
72
+ "python-dev"
73
+ ]
74
+ }
75
+ },
76
+ "resources": [
77
+ "file://.kiro/steering/code-conventions.md",
78
+ "file://.kiro/steering/oci-media-types.md",
79
+ "file://AGENTS.md",
80
+ "file://FEATURES.md"
81
+ ],
82
+ "hooks": {},
83
+ "keyboardShortcut": "ctrl+shift+p",
84
+ "welcomeMessage": "Planner ready. I'll locate TODOs, build a plan, and hand off to python-dev. I don't write code."
85
+ }
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "python-dev",
3
+ "description": "Senior Python developer agent for building tooling.",
4
+ "prompt": " You are a senior Python developer. You build tooling based on user instructions. When requirements are ambiguous, incomplete, or admit multiple valid implementation choices, stop and ask before proceeding — do not guess. Work in small increments: implement one small block, then verify it (automated test or manual check) before moving to the next block. Always use the project's virtualenv when running Python or tools. Invoke via uv run <cmd> or .venv/bin/<cmd> — never via a bare python, pytest, or ruff that could resolve to a global installation.",
5
+ "mcpServers": {},
6
+ "tools": [
7
+ "*"
8
+ ],
9
+ "toolAliases": {},
10
+ "allowedTools": [
11
+ "code",
12
+ "fs_read",
13
+ "fs_write",
14
+ "glob",
15
+ "grep",
16
+ "tool_search",
17
+ "delegate",
18
+ "knowledge",
19
+ "todo"
20
+ ],
21
+ "resources": [
22
+ "file://.kiro/steering/code-conventions.md",
23
+ "file://AGENTS.md",
24
+ "skill://~/.kiro/skills/*/SKILL.md"
25
+ ],
26
+ "hooks": {},
27
+ "toolsSettings": {
28
+ "read": {
29
+ "allowedPaths": [
30
+ "**"
31
+ ]
32
+ },
33
+ "write": {
34
+ "allowedPaths": [
35
+ "**"
36
+ ]
37
+ },
38
+ "execute_bash": {
39
+ "autoAllowReadonly": true,
40
+ "allowedCommands": [
41
+ "diff.*",
42
+ "find . .*",
43
+ "gh.*",
44
+ "git.*",
45
+ "grep.*",
46
+ "ls.*",
47
+ "make.*",
48
+ "pdm.*",
49
+ "podman.*",
50
+ "sed.*",
51
+ "source .venv/bin/activate.*",
52
+ "timeout.*",
53
+ "true.*",
54
+ "uv.*"
55
+ ]
56
+ }
57
+ },
58
+ "includeMcpJson": true,
59
+ "model": null
60
+ }
@@ -0,0 +1,88 @@
1
+ ---
2
+ name: code-quality-enhancement
3
+ description: >
4
+ Find and fix code quality regressions in margot: ruff lint violations, low test
5
+ coverage, and global (non-selective) imports. Use when asked to improve code
6
+ quality, clean up lint, raise coverage, or fix import style — not on every
7
+ request.
8
+ ---
9
+
10
+ # Code Quality Enhancement Skill
11
+
12
+ Three independent triggers, each with its own workflow. Run only the one(s) the
13
+ user asked for — do not run all three unless explicitly asked to do a full pass.
14
+
15
+ ## When to use
16
+
17
+ Only when explicitly asked to improve code quality, fix lint, raise test coverage, or
18
+ fix import style. Do not run proactively during unrelated feature or bugfix work.
19
+
20
+ ## Trigger 1 — ruff lint
21
+
22
+ 1. Run `make lint` (`ruff check --no-fix src/ tests/`) and capture the full output.
23
+ 2. Read each flagged file's surrounding context — not just the flagged line — before
24
+ deciding on a fix.
25
+ 3. Build a plan grouped by rule code, not a one-off patch per line.
26
+ 4. For each violation, decide real fix vs. suppress-with-`noqa`:
27
+ - **Default to a real fix.** `select = ["ALL"]` in `pyproject.toml` is deliberate —
28
+ the project wants the strict ruleset enforced, not relaxed.
29
+ - **`# noqa` is legitimate only when:** the rule is a false positive for this exact
30
+ case, or fixing it would fight an established pattern already accepted in
31
+ `pyproject.toml`'s `ignore` list philosophy (e.g. Typer's bool positional args,
32
+ inline exception messages). If in doubt, treat it as a case-by-case judgment,
33
+ not a default — document the reason in the `noqa` comment
34
+ (`# noqa: RULE — reason`).
35
+ - **Never blanket-suppress** a whole file or add a rule to the project-wide
36
+ `ignore` list to make a violation disappear. That is a scope decision for the
37
+ user, not an automatic fix.
38
+ 5. Delegate the grouped fix plan to the `python-dev` agent with the plan, affected
39
+ files, and the ruff rule codes involved.
40
+ 6. Definition of done: `make lint` passes clean, changes committed.
41
+
42
+ ## Trigger 2 — low test coverage
43
+
44
+ 1. Run `make test` (`uv run pytest`, which already runs with
45
+ `--cov=margot --cov-report=term-missing --cov-fail-under=90`) and capture the
46
+ per-file coverage table from the terminal report.
47
+ 2. Select the 1-2 files with the lowest coverage — not every under-covered file at
48
+ once. Read the file and its existing test file (if any) to see what's actually
49
+ untested (the `Missing` line-number ranges in the report point at this directly).
50
+ 3. Build a short plan: what behavior is untested, what test(s) to add, which file(s)
51
+ they land in (mirror the existing `tests/unit/` / `tests/integration/` /
52
+ `tests/e2e/` split already used in this repo).
53
+ 4. Delegate to `python-dev` with the plan and the specific uncovered line ranges.
54
+ Tests must assert real behavior — no stub tests that just exercise a line without
55
+ checking an outcome (same TDD rule as `code-conventions.md`).
56
+ 5. Definition of done: `make test` passes, coverage for the targeted file(s)
57
+ measurably improves, changes committed.
58
+
59
+ ## Trigger 3 — global (non-selective) imports
60
+
61
+ 1. Search for violations:
62
+ ```bash
63
+ grep -rn -E "^import " src/ tests/
64
+ ```
65
+ This catches `import x` module-level imports; selective imports (`from x import y`)
66
+ are the required convention (see `code-conventions.md`) and won't match.
67
+ 2. For each match, check whether a selective form is actually possible — a handful of
68
+ modules are conventionally imported as a namespace (e.g. `import margot.console as
69
+ console`, which the project's own conventions explicitly require — don't "fix" that
70
+ one). Distinguish real violations from accepted namespace-import patterns before
71
+ planning a change.
72
+ 3. Build a plan: for each real violation, the selective import form it should become,
73
+ and every usage site in that file that needs updating to match (e.g. `pytest.raises`
74
+ → `from pytest import raises` then all call sites).
75
+ 4. Delegate to `python-dev` with the plan and file list.
76
+ 5. Definition of done: `grep -rn -E "^import " src/ tests/` shows only accepted
77
+ namespace-import patterns, `make lint` and `make test` still pass, changes
78
+ committed.
79
+
80
+ ## Common rules across all three triggers
81
+
82
+ - Always run the relevant `make` target yourself first — don't plan from memory or
83
+ assumption of what's currently failing.
84
+ - Group fixes into a coherent plan before delegating; don't delegate raw tool output.
85
+ - Delegate implementation to `python-dev` — this skill does not write code directly.
86
+ - A trigger is not done until its verification command passes clean and the fix is
87
+ committed (conventional commit format), matching the repo's definition-of-done
88
+ pattern used elsewhere (sprints, TODO fixes).
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: fix-todos
3
+ description: >
4
+ Locate, plan, and delegate fixes for # TODO(kiro): markers in the margot codebase.
5
+ Use only when explicitly asked to find, review, or fix TODOs — not on every planning
6
+ request.
7
+ ---
8
+
9
+ # Fix TODOs Skill
10
+
11
+ ## When to use
12
+
13
+ Only when the user explicitly asks to find, triage, or fix TODO markers. Do not run
14
+ this workflow proactively on unrelated planning or implementation requests.
15
+
16
+ ## Workflow
17
+
18
+ 1. Search for TODO markers:
19
+ ```bash
20
+ grep -rn "# TODO" --include="*.py" src/ tests/
21
+ ```
22
+ Any author tag counts (`TODO(kiro):`, `TODO(<other>):`, bare `TODO:`) — bare TODOs are
23
+ a convention violation to flag, not to ignore (see `code-conventions.md`).
24
+ 2. For each TODO found, read the surrounding function/class to understand what's
25
+ actually required — the TODO text alone is often incomplete context.
26
+ 3. **If a TODO is ambiguous, or its fix implies a design decision (API shape, new
27
+ dependency, behavior change, breaking change), stop and ask the user before
28
+ proceeding.** Do not guess intent and do not delegate a design decision to the dev
29
+ agent — that decision is the user's to make, the same way sprint planning decisions
30
+ in this repo are locked with the user first.
31
+ 4. Group related, unambiguous TODOs (same file, same feature) into a single plan rather
32
+ than one-off patches.
33
+ 5. Build a short plan per group: what changes, which files, what test proves it's done.
34
+ 6. Delegate implementation to the `python-dev` agent with the plan, file paths, and a
35
+ definition of done: tests pass, the TODO marker is removed, changes are committed
36
+ (conventional commit format).
37
+ 7. Report back what was fixed and confirm no `# TODO` markers remain in the touched
38
+ scope.
39
+
40
+ ## Conventions this enforces
41
+
42
+ - Correct format is `# TODO(kiro): ...` (ruff TD002) — bare `# TODO:` must be fixed to
43
+ include an author tag, not just left as-is.
44
+ - A TODO is not "done" until removed from source and its fix is committed — matching
45
+ the sprint definition-of-done rule ("No `# TODO` markers left from this sprint's work").
46
+
47
+ ## Scope
48
+
49
+ Source and test files only (`src/`, `tests/`). Do not treat TODO-shaped text inside
50
+ `.kiro/steering/*.md` or sprint docs as code TODOs to fix — those are conventions
51
+ references, not action items.