krita-cli 1.0.0__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.
- krita_cli-1.0.0/.github/skills/krita-mcp.md +151 -0
- krita_cli-1.0.0/.github/workflows/ci.yml +113 -0
- krita_cli-1.0.0/.gitignore +40 -0
- krita_cli-1.0.0/.pre-commit-config.yaml +17 -0
- krita_cli-1.0.0/.python-version +1 -0
- krita_cli-1.0.0/LICENSE +21 -0
- krita_cli-1.0.0/PKG-INFO +103 -0
- krita_cli-1.0.0/README.md +70 -0
- krita_cli-1.0.0/SECRETS.md +28 -0
- krita_cli-1.0.0/benchmarks/test_rendering.py +67 -0
- krita_cli-1.0.0/conda-recipe/meta.yaml +48 -0
- krita_cli-1.0.0/conductor/archive/cli_command_grouping_20260406/index.md +5 -0
- krita_cli-1.0.0/conductor/archive/cli_command_grouping_20260406/metadata.json +7 -0
- krita_cli-1.0.0/conductor/archive/cli_command_grouping_20260406/plan.md +21 -0
- krita_cli-1.0.0/conductor/archive/cli_command_grouping_20260406/spec.md +22 -0
- krita_cli-1.0.0/conductor/archive/command_history_replay_20260405/index.md +5 -0
- krita_cli-1.0.0/conductor/archive/command_history_replay_20260405/metadata.json +8 -0
- krita_cli-1.0.0/conductor/archive/command_history_replay_20260405/plan.md +33 -0
- krita_cli-1.0.0/conductor/archive/command_history_replay_20260405/spec.md +34 -0
- krita_cli-1.0.0/conductor/archive/e2e_test_infrastructure_20260406/index.md +5 -0
- krita_cli-1.0.0/conductor/archive/e2e_test_infrastructure_20260406/metadata.json +7 -0
- krita_cli-1.0.0/conductor/archive/e2e_test_infrastructure_20260406/plan.md +14 -0
- krita_cli-1.0.0/conductor/archive/e2e_test_infrastructure_20260406/spec.md +24 -0
- krita_cli-1.0.0/conductor/archive/mcp_tool_discovery_20260406/index.md +5 -0
- krita_cli-1.0.0/conductor/archive/mcp_tool_discovery_20260406/metadata.json +7 -0
- krita_cli-1.0.0/conductor/archive/mcp_tool_discovery_20260406/plan.md +4 -0
- krita_cli-1.0.0/conductor/archive/mcp_tool_discovery_20260406/spec.md +22 -0
- krita_cli-1.0.0/conductor/archive/protocol_versioning_v2_20260406/index.md +5 -0
- krita_cli-1.0.0/conductor/archive/protocol_versioning_v2_20260406/metadata.json +7 -0
- krita_cli-1.0.0/conductor/archive/protocol_versioning_v2_20260406/plan.md +6 -0
- krita_cli-1.0.0/conductor/archive/protocol_versioning_v2_20260406/spec.md +24 -0
- krita_cli-1.0.0/conductor/archive/rollback_mechanisms_20260405/index.md +5 -0
- krita_cli-1.0.0/conductor/archive/rollback_mechanisms_20260405/metadata.json +8 -0
- krita_cli-1.0.0/conductor/archive/rollback_mechanisms_20260405/plan.md +23 -0
- krita_cli-1.0.0/conductor/archive/rollback_mechanisms_20260405/spec.md +33 -0
- krita_cli-1.0.0/conductor/archive/security_limits_validation_20260406/index.md +5 -0
- krita_cli-1.0.0/conductor/archive/security_limits_validation_20260406/metadata.json +7 -0
- krita_cli-1.0.0/conductor/archive/security_limits_validation_20260406/plan.md +16 -0
- krita_cli-1.0.0/conductor/archive/security_limits_validation_20260406/spec.md +31 -0
- krita_cli-1.0.0/conductor/archive/selection_advanced_features_20260406/index.md +5 -0
- krita_cli-1.0.0/conductor/archive/selection_advanced_features_20260406/metadata.json +7 -0
- krita_cli-1.0.0/conductor/archive/selection_advanced_features_20260406/plan.md +28 -0
- krita_cli-1.0.0/conductor/archive/selection_advanced_features_20260406/spec.md +27 -0
- krita_cli-1.0.0/conductor/archive/selection_clipping_integration_20260406/index.md +5 -0
- krita_cli-1.0.0/conductor/archive/selection_clipping_integration_20260406/metadata.json +7 -0
- krita_cli-1.0.0/conductor/archive/selection_clipping_integration_20260406/plan.md +19 -0
- krita_cli-1.0.0/conductor/archive/selection_clipping_integration_20260406/spec.md +31 -0
- krita_cli-1.0.0/conductor/archive/selection_persistence_20260406/index.md +5 -0
- krita_cli-1.0.0/conductor/archive/selection_persistence_20260406/metadata.json +7 -0
- krita_cli-1.0.0/conductor/archive/selection_persistence_20260406/plan.md +30 -0
- krita_cli-1.0.0/conductor/archive/selection_persistence_20260406/spec.md +27 -0
- krita_cli-1.0.0/conductor/archive/selection_quality_coverage_20260406/index.md +5 -0
- krita_cli-1.0.0/conductor/archive/selection_quality_coverage_20260406/metadata.json +7 -0
- krita_cli-1.0.0/conductor/archive/selection_quality_coverage_20260406/plan.md +14 -0
- krita_cli-1.0.0/conductor/archive/selection_quality_coverage_20260406/spec.md +35 -0
- krita_cli-1.0.0/conductor/archive/selection_transforms_modifiers_20260406/index.md +5 -0
- krita_cli-1.0.0/conductor/archive/selection_transforms_modifiers_20260406/metadata.json +7 -0
- krita_cli-1.0.0/conductor/archive/selection_transforms_modifiers_20260406/plan.md +14 -0
- krita_cli-1.0.0/conductor/archive/selection_transforms_modifiers_20260406/spec.md +25 -0
- krita_cli-1.0.0/conductor/code_styleguides/python.md +64 -0
- krita_cli-1.0.0/conductor/index.md +14 -0
- krita_cli-1.0.0/conductor/product-guidelines.md +54 -0
- krita_cli-1.0.0/conductor/product.md +62 -0
- krita_cli-1.0.0/conductor/tech-stack.md +119 -0
- krita_cli-1.0.0/conductor/tracks/implement_batch_operations_endpoint_20260405/index.md +5 -0
- krita_cli-1.0.0/conductor/tracks/implement_batch_operations_endpoint_20260405/metadata.json +8 -0
- krita_cli-1.0.0/conductor/tracks/implement_batch_operations_endpoint_20260405/plan.md +23 -0
- krita_cli-1.0.0/conductor/tracks/implement_batch_operations_endpoint_20260405/spec.md +16 -0
- krita_cli-1.0.0/conductor/tracks/performance_benchmarking_ci_20260406/index.md +5 -0
- krita_cli-1.0.0/conductor/tracks/performance_benchmarking_ci_20260406/metadata.json +7 -0
- krita_cli-1.0.0/conductor/tracks/performance_benchmarking_ci_20260406/plan.md +6 -0
- krita_cli-1.0.0/conductor/tracks/performance_benchmarking_ci_20260406/spec.md +24 -0
- krita_cli-1.0.0/conductor/tracks/selection_tools_20260406/index.md +5 -0
- krita_cli-1.0.0/conductor/tracks/selection_tools_20260406/metadata.json +7 -0
- krita_cli-1.0.0/conductor/tracks/selection_tools_20260406/plan.md +23 -0
- krita_cli-1.0.0/conductor/tracks/selection_tools_20260406/spec.md +31 -0
- krita_cli-1.0.0/conductor/tracks/windows_testing_20260406/index.md +5 -0
- krita_cli-1.0.0/conductor/tracks/windows_testing_20260406/metadata.json +7 -0
- krita_cli-1.0.0/conductor/tracks/windows_testing_20260406/plan.md +5 -0
- krita_cli-1.0.0/conductor/tracks/windows_testing_20260406/spec.md +24 -0
- krita_cli-1.0.0/conductor/tracks.md +14 -0
- krita_cli-1.0.0/conductor/workflow.md +110 -0
- krita_cli-1.0.0/fix_cli_tests.py +29 -0
- krita_cli-1.0.0/krita-plugin/kritamcp/__init__.py +2169 -0
- krita_cli-1.0.0/krita-plugin/kritamcp/history_store.py +68 -0
- krita_cli-1.0.0/krita-plugin/kritamcp/payload_validator.py +23 -0
- krita_cli-1.0.0/krita-plugin/kritamcp/rate_limiter.py +53 -0
- krita_cli-1.0.0/krita-plugin/kritamcp/snapshot_store.py +113 -0
- krita_cli-1.0.0/krita-plugin/kritamcp.desktop +8 -0
- krita_cli-1.0.0/pyproject.toml +284 -0
- krita_cli-1.0.0/renovate.json +56 -0
- krita_cli-1.0.0/requirements.txt +2 -0
- krita_cli-1.0.0/src/krita_cli/__init__.py +5 -0
- krita_cli-1.0.0/src/krita_cli/_shared.py +94 -0
- krita_cli-1.0.0/src/krita_cli/app.py +149 -0
- krita_cli-1.0.0/src/krita_cli/cli.py +59 -0
- krita_cli-1.0.0/src/krita_cli/commands/__init__.py +1 -0
- krita_cli-1.0.0/src/krita_cli/commands/batch.py +86 -0
- krita_cli-1.0.0/src/krita_cli/commands/brush.py +58 -0
- krita_cli-1.0.0/src/krita_cli/commands/call.py +49 -0
- krita_cli-1.0.0/src/krita_cli/commands/canvas.py +77 -0
- krita_cli-1.0.0/src/krita_cli/commands/color.py +42 -0
- krita_cli-1.0.0/src/krita_cli/commands/config.py +48 -0
- krita_cli-1.0.0/src/krita_cli/commands/file_ops.py +27 -0
- krita_cli-1.0.0/src/krita_cli/commands/health.py +32 -0
- krita_cli-1.0.0/src/krita_cli/commands/history_cmd.py +64 -0
- krita_cli-1.0.0/src/krita_cli/commands/introspect.py +46 -0
- krita_cli-1.0.0/src/krita_cli/commands/layers.py +112 -0
- krita_cli-1.0.0/src/krita_cli/commands/navigation.py +33 -0
- krita_cli-1.0.0/src/krita_cli/commands/replay.py +126 -0
- krita_cli-1.0.0/src/krita_cli/commands/rollback.py +39 -0
- krita_cli-1.0.0/src/krita_cli/commands/selection.py +364 -0
- krita_cli-1.0.0/src/krita_cli/commands/stroke.py +101 -0
- krita_cli-1.0.0/src/krita_cli/config_cmd.py +68 -0
- krita_cli-1.0.0/src/krita_cli/history.py +198 -0
- krita_cli-1.0.0/src/krita_client/__init__.py +68 -0
- krita_cli-1.0.0/src/krita_client/client.py +690 -0
- krita_cli-1.0.0/src/krita_client/config.py +53 -0
- krita_cli-1.0.0/src/krita_client/models.py +507 -0
- krita_cli-1.0.0/src/krita_client/schema.py +109 -0
- krita_cli-1.0.0/src/krita_mcp/__init__.py +1 -0
- krita_cli-1.0.0/src/krita_mcp/server.py +1022 -0
- krita_cli-1.0.0/tests/__init__.py +0 -0
- krita_cli-1.0.0/tests/conftest.py +9 -0
- krita_cli-1.0.0/tests/e2e/__init__.py +0 -0
- krita_cli-1.0.0/tests/e2e/conftest.py +328 -0
- krita_cli-1.0.0/tests/e2e/test_e2e.py +69 -0
- krita_cli-1.0.0/tests/e2e/test_e2e_mock.py +232 -0
- krita_cli-1.0.0/tests/integration/__init__.py +0 -0
- krita_cli-1.0.0/tests/integration/test_api_capabilities.py +127 -0
- krita_cli-1.0.0/tests/integration/test_batch_cli.py +120 -0
- krita_cli-1.0.0/tests/integration/test_batch_client.py +81 -0
- krita_cli-1.0.0/tests/integration/test_cli.py +51 -0
- krita_cli-1.0.0/tests/integration/test_cli_coverage.py +202 -0
- krita_cli-1.0.0/tests/integration/test_cli_error_paths.py +133 -0
- krita_cli-1.0.0/tests/integration/test_cli_full.py +272 -0
- krita_cli-1.0.0/tests/integration/test_cli_success.py +132 -0
- krita_cli-1.0.0/tests/integration/test_config_cli.py +54 -0
- krita_cli-1.0.0/tests/integration/test_config_cmd_cli.py +86 -0
- krita_cli-1.0.0/tests/integration/test_history_cli.py +54 -0
- krita_cli-1.0.0/tests/integration/test_history_endpoint.py +59 -0
- krita_cli-1.0.0/tests/integration/test_introspect_cli.py +60 -0
- krita_cli-1.0.0/tests/integration/test_layers_cli.py +142 -0
- krita_cli-1.0.0/tests/integration/test_mcp_coverage.py +117 -0
- krita_cli-1.0.0/tests/integration/test_mcp_error_coverage.py +276 -0
- krita_cli-1.0.0/tests/integration/test_mcp_error_result.py +205 -0
- krita_cli-1.0.0/tests/integration/test_mcp_full.py +156 -0
- krita_cli-1.0.0/tests/integration/test_mcp_remaining_tools.py +152 -0
- krita_cli-1.0.0/tests/integration/test_mcp_selection_tools.py +149 -0
- krita_cli-1.0.0/tests/integration/test_mcp_server.py +211 -0
- krita_cli-1.0.0/tests/integration/test_mcp_success.py +318 -0
- krita_cli-1.0.0/tests/integration/test_replay_cli.py +90 -0
- krita_cli-1.0.0/tests/integration/test_rollback.py +66 -0
- krita_cli-1.0.0/tests/integration/test_rollback_cli.py +35 -0
- krita_cli-1.0.0/tests/integration/test_security_limits.py +76 -0
- krita_cli-1.0.0/tests/integration/test_selection_advanced.py +54 -0
- krita_cli-1.0.0/tests/integration/test_selection_cli_coverage.py +230 -0
- krita_cli-1.0.0/tests/integration/test_selection_client.py +114 -0
- krita_cli-1.0.0/tests/integration/test_selection_persistence.py +78 -0
- krita_cli-1.0.0/tests/property/__init__.py +0 -0
- krita_cli-1.0.0/tests/property/test_input_sanitization.py +182 -0
- krita_cli-1.0.0/tests/property/test_models.py +190 -0
- krita_cli-1.0.0/tests/property/test_selection.py +110 -0
- krita_cli-1.0.0/tests/test_phase_11.py +41 -0
- krita_cli-1.0.0/tests/unit/__init__.py +0 -0
- krita_cli-1.0.0/tests/unit/test_batch_models.py +74 -0
- krita_cli-1.0.0/tests/unit/test_client.py +267 -0
- krita_cli-1.0.0/tests/unit/test_client_coverage.py +272 -0
- krita_cli-1.0.0/tests/unit/test_client_internal.py +21 -0
- krita_cli-1.0.0/tests/unit/test_config.py +34 -0
- krita_cli-1.0.0/tests/unit/test_config_cmd.py +100 -0
- krita_cli-1.0.0/tests/unit/test_error_codes.py +151 -0
- krita_cli-1.0.0/tests/unit/test_history_store.py +188 -0
- krita_cli-1.0.0/tests/unit/test_mcp_batch.py +57 -0
- krita_cli-1.0.0/tests/unit/test_mcp_history_tool.py +61 -0
- krita_cli-1.0.0/tests/unit/test_models.py +340 -0
- krita_cli-1.0.0/tests/unit/test_payload_validator.py +44 -0
- krita_cli-1.0.0/tests/unit/test_replay_cmd.py +77 -0
- krita_cli-1.0.0/tests/unit/test_rollback_client.py +63 -0
- krita_cli-1.0.0/tests/unit/test_rollback_models.py +44 -0
- krita_cli-1.0.0/tests/unit/test_schema.py +41 -0
- krita_cli-1.0.0/tests/unit/test_security_config.py +105 -0
- krita_cli-1.0.0/tests/unit/test_selection_advanced_models.py +73 -0
- krita_cli-1.0.0/tests/unit/test_selection_models.py +216 -0
- krita_cli-1.0.0/tests/unit/test_selection_persistence_models.py +65 -0
- krita_cli-1.0.0/tests/unit/test_shared_coverage.py +48 -0
- krita_cli-1.0.0/tests/unit/test_snapshot_store.py +90 -0
- krita_cli-1.0.0/tests/unit/test_type_safety_coverage.py +193 -0
- krita_cli-1.0.0/types/krita/__init__.pyi +191 -0
- krita_cli-1.0.0/uv.lock +2358 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Krita MCP — Skill Reference
|
|
2
|
+
|
|
3
|
+
## What is this?
|
|
4
|
+
|
|
5
|
+
A **SOTA CLI + MCP server** for programmatic painting in Krita. Two interfaces, one core:
|
|
6
|
+
- **CLI**: `krita stroke --points 100,100 200,200` — direct command-line control
|
|
7
|
+
- **MCP**: FastMCP server — for AI agents to paint programmatically
|
|
8
|
+
|
|
9
|
+
Both talk to a Krita plugin via HTTP on localhost:5678.
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### Prerequisites
|
|
14
|
+
- Python 3.12+
|
|
15
|
+
- Krita installed with MCP plugin enabled
|
|
16
|
+
- `uv` package manager
|
|
17
|
+
|
|
18
|
+
### Setup
|
|
19
|
+
```bash
|
|
20
|
+
uv sync
|
|
21
|
+
# Copy plugin to Krita's plugin directory
|
|
22
|
+
# Enable in Krita: Settings → Configure Krita → Python Plugin Manager
|
|
23
|
+
# Start Krita with plugin enabled
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### CLI Usage
|
|
27
|
+
```bash
|
|
28
|
+
# Check Krita is running
|
|
29
|
+
krita health
|
|
30
|
+
|
|
31
|
+
# Create a canvas
|
|
32
|
+
krita canvas new-canvas --width 1920 --height 1080
|
|
33
|
+
|
|
34
|
+
# Set color and draw
|
|
35
|
+
krita color set-color --color "#ff0000"
|
|
36
|
+
krita stroke stroke "0,0" "100,100" "200,50"
|
|
37
|
+
|
|
38
|
+
# Select and draw within bounds
|
|
39
|
+
krita selection select-rect --x 10 --y 10 --width 100 --height 100
|
|
40
|
+
krita stroke stroke "0,0" "200,200" # clipped to selection
|
|
41
|
+
|
|
42
|
+
# Export canvas
|
|
43
|
+
krita canvas get-canvas --filename output.png
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### MCP Usage
|
|
47
|
+
|
|
48
|
+
Connect an MCP client (Claude, etc.) to `http://localhost:5678`. Available tools:
|
|
49
|
+
|
|
50
|
+
| Tool | Description |
|
|
51
|
+
|------|-------------|
|
|
52
|
+
| `krita_health` | Check Krita + plugin status |
|
|
53
|
+
| `krita_new_canvas` | Create canvas (width, height, bg color) |
|
|
54
|
+
| `krita_set_color` | Set foreground color (hex) |
|
|
55
|
+
| `krita_set_brush` | Set brush preset/size/opacity |
|
|
56
|
+
| `krita_stroke` | Paint stroke through [x, y] points |
|
|
57
|
+
| `krita_fill` | Fill circular area |
|
|
58
|
+
| `krita_draw_shape` | Draw rectangle/ellipse/line |
|
|
59
|
+
| `krita_get_canvas` | Export canvas to PNG |
|
|
60
|
+
| `krita_save` | Save canvas to file |
|
|
61
|
+
| `krita_undo` / `krita_redo` | Undo/redo |
|
|
62
|
+
| `krita_clear` | Clear canvas |
|
|
63
|
+
| `krita_get_color_at` | Eyedropper |
|
|
64
|
+
| `krita_list_brushes` | List brush presets |
|
|
65
|
+
| `krita_open_file` | Open existing file |
|
|
66
|
+
| `krita_batch` | Execute multiple commands sequentially |
|
|
67
|
+
| `krita_rollback` | Roll back a batch operation by batch ID |
|
|
68
|
+
| `krita_select_rect` | Select a rectangular area |
|
|
69
|
+
| `krita_select_ellipse` | Select an elliptical area |
|
|
70
|
+
| `krita_select_polygon` | Select a polygonal area |
|
|
71
|
+
| `krita_selection_info` | Get current selection bounds |
|
|
72
|
+
| `krita_invert_selection` | Invert the current selection |
|
|
73
|
+
| `krita_clear_selection` | Clear selection contents |
|
|
74
|
+
| `krita_fill_selection` | Fill selection with foreground color |
|
|
75
|
+
| `krita_deselect` | Remove current selection |
|
|
76
|
+
| `krita_transform_selection` | Move/rotate/scale selection |
|
|
77
|
+
| `krita_grow_selection` | Grow selection by N pixels |
|
|
78
|
+
| `krita_shrink_selection` | Shrink selection by N pixels |
|
|
79
|
+
| `krita_border_selection` | Create border around selection |
|
|
80
|
+
| `krita_get_capabilities` | Get detected API capabilities |
|
|
81
|
+
| `krita_security_status` | Get security limits and usage |
|
|
82
|
+
| `krita_list_tools` | List all available MCP tools |
|
|
83
|
+
|
|
84
|
+
## Agent Workflow
|
|
85
|
+
|
|
86
|
+
### Painting a simple shape
|
|
87
|
+
1. `krita_new_canvas(width=800, height=600)` — create canvas
|
|
88
|
+
2. `krita_set_color(color="#ff0000")` — set color
|
|
89
|
+
3. `krita_stroke(points=[[100,100],[200,100],[150,200]])` — draw triangle
|
|
90
|
+
4. `krita_get_canvas(filename="result.png")` — export result
|
|
91
|
+
|
|
92
|
+
### Painting within a selection
|
|
93
|
+
1. `krita_new_canvas(width=800, height=600)`
|
|
94
|
+
2. `krita_select_rect(x=50, y=50, width=200, height=200)` — create selection
|
|
95
|
+
3. `krita_set_color(color="#00ff00")`
|
|
96
|
+
4. `krita_stroke(points=[[0,0],[400,400]])` — clipped to selection
|
|
97
|
+
5. `krita_deselect()` — remove selection
|
|
98
|
+
6. `krita_get_canvas(filename="clipped.png")`
|
|
99
|
+
|
|
100
|
+
### Batch operations
|
|
101
|
+
1. `krita_batch(commands=[{"action":"set_color","params":{"color":"#ff0000"}},{"action":"stroke","params":{"points":[[0,0],[100,100]]}}])`
|
|
102
|
+
2. `krita_rollback(batch_id="...")` — if something went wrong
|
|
103
|
+
|
|
104
|
+
### Iterative painting
|
|
105
|
+
1. `krita_new_canvas()` → `krita_stroke()` → `krita_get_canvas()` — see result
|
|
106
|
+
2. Analyze result, adjust parameters
|
|
107
|
+
3. `krita_stroke()` with new points → `krita_get_canvas()` — iterate
|
|
108
|
+
4. `krita_save(path="final.png")` when satisfied
|
|
109
|
+
|
|
110
|
+
## Security Limits
|
|
111
|
+
|
|
112
|
+
| Limit | Default |
|
|
113
|
+
|-------|---------|
|
|
114
|
+
| Rate limit | 60 commands/minute |
|
|
115
|
+
| Max payload | 10 MB |
|
|
116
|
+
| Max batch size | 50 commands |
|
|
117
|
+
| Max canvas | 8192×8192 |
|
|
118
|
+
| Max layers | 100 |
|
|
119
|
+
|
|
120
|
+
Check current status: `krita selection security-status`
|
|
121
|
+
|
|
122
|
+
## Command Groups
|
|
123
|
+
|
|
124
|
+
| Group | Commands |
|
|
125
|
+
|-------|----------|
|
|
126
|
+
| `krita canvas` | new-canvas, get-canvas, save, clear |
|
|
127
|
+
| `krita color` | set-color, get-color-at |
|
|
128
|
+
| `krita brush` | set-brush, list-brushes |
|
|
129
|
+
| `krita stroke` | stroke, fill, draw-shape |
|
|
130
|
+
| `krita navigation` | undo, redo |
|
|
131
|
+
| `krita file` | open-file |
|
|
132
|
+
| `krita selection` | select-rect, select-ellipse, select-polygon, selection-info, transform-selection, grow-selection, shrink-selection, border-selection, select-clear, select-invert, select-fill, deselect, security-status |
|
|
133
|
+
| `krita history` | history |
|
|
134
|
+
| `krita introspect` | canvas-info, current-color, current-brush |
|
|
135
|
+
| `krita replay` | replay |
|
|
136
|
+
|
|
137
|
+
## Error Handling
|
|
138
|
+
|
|
139
|
+
All commands return structured errors:
|
|
140
|
+
```json
|
|
141
|
+
{"code": "NO_ACTIVE_DOCUMENT", "message": "...", "recoverable": true}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
CLI shows: `[red]Error: ...[/red]` with hints for recovery.
|
|
145
|
+
|
|
146
|
+
## Protocol
|
|
147
|
+
|
|
148
|
+
- HTTP POST to `localhost:5678` with `{"action": "...", "params": {...}}`
|
|
149
|
+
- Health check: GET `localhost:5678/health`
|
|
150
|
+
- Default timeout: 30s (120s for export/save)
|
|
151
|
+
- Protocol version included in health response
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
tags: ["v*"]
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: [main, master]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
env:
|
|
12
|
+
UV_VERSION: "latest"
|
|
13
|
+
PYTHON_VERSION: "3.12"
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
lint:
|
|
17
|
+
name: Lint (ruff)
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
- uses: astral-sh/setup-uv@v5
|
|
22
|
+
with:
|
|
23
|
+
version: ${{ env.UV_VERSION }}
|
|
24
|
+
- uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
27
|
+
- run: uv sync --frozen
|
|
28
|
+
- run: uv run ruff check src/ tests/
|
|
29
|
+
- run: uv run ruff format --check src/ tests/
|
|
30
|
+
|
|
31
|
+
typecheck:
|
|
32
|
+
name: Type Check (ty)
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
- uses: astral-sh/setup-uv@v5
|
|
37
|
+
with:
|
|
38
|
+
version: ${{ env.UV_VERSION }}
|
|
39
|
+
- uses: actions/setup-python@v5
|
|
40
|
+
with:
|
|
41
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
42
|
+
- run: uv sync --frozen
|
|
43
|
+
- run: uv run ty check src/ types/
|
|
44
|
+
|
|
45
|
+
test:
|
|
46
|
+
name: All Tests
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
strategy:
|
|
49
|
+
matrix:
|
|
50
|
+
python-version: ["3.12", "3.13"]
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/checkout@v4
|
|
53
|
+
- uses: astral-sh/setup-uv@v5
|
|
54
|
+
with:
|
|
55
|
+
version: ${{ env.UV_VERSION }}
|
|
56
|
+
- uses: actions/setup-python@v5
|
|
57
|
+
with:
|
|
58
|
+
python-version: ${{ matrix.python-version }}
|
|
59
|
+
- run: uv sync --frozen
|
|
60
|
+
- run: uv run pytest tests/ -v --cov=src --cov-fail-under=95
|
|
61
|
+
|
|
62
|
+
build:
|
|
63
|
+
name: Build Package
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
needs: [lint, typecheck, test]
|
|
66
|
+
steps:
|
|
67
|
+
- uses: actions/checkout@v4
|
|
68
|
+
- uses: astral-sh/setup-uv@v5
|
|
69
|
+
with:
|
|
70
|
+
version: ${{ env.UV_VERSION }}
|
|
71
|
+
- run: uv build
|
|
72
|
+
- uses: actions/upload-artifact@v4
|
|
73
|
+
with:
|
|
74
|
+
name: dist
|
|
75
|
+
path: dist/
|
|
76
|
+
|
|
77
|
+
publish-pypi:
|
|
78
|
+
name: Publish to PyPI
|
|
79
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
80
|
+
needs: [build]
|
|
81
|
+
runs-on: ubuntu-latest
|
|
82
|
+
environment:
|
|
83
|
+
name: pypi
|
|
84
|
+
url: https://pypi.org/p/krita-cli
|
|
85
|
+
permissions:
|
|
86
|
+
id-token: write
|
|
87
|
+
steps:
|
|
88
|
+
- uses: actions/download-artifact@v4
|
|
89
|
+
with:
|
|
90
|
+
name: dist
|
|
91
|
+
path: dist/
|
|
92
|
+
- name: Publish to PyPI
|
|
93
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
94
|
+
|
|
95
|
+
publish-conda:
|
|
96
|
+
name: Publish to Conda
|
|
97
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
98
|
+
needs: [build]
|
|
99
|
+
runs-on: ubuntu-latest
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/checkout@v4
|
|
102
|
+
- name: Set up Conda
|
|
103
|
+
uses: conda-incubator/setup-miniconda@v3
|
|
104
|
+
with:
|
|
105
|
+
auto-update-conda: true
|
|
106
|
+
python-version: 3.12
|
|
107
|
+
channels: conda-forge,defaults
|
|
108
|
+
- name: Build and Upload to Anaconda
|
|
109
|
+
shell: bash -l {0}
|
|
110
|
+
run: |
|
|
111
|
+
conda install -y anaconda-client conda-build
|
|
112
|
+
conda build conda-recipe/ --output-folder dist/conda
|
|
113
|
+
anaconda -t ${{ secrets.ANACONDA_API_TOKEN }} upload dist/conda/noarch/krita-cli-*.tar.bz2 --force
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
.env
|
|
5
|
+
|
|
6
|
+
# Build artifacts
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
*.egg
|
|
11
|
+
|
|
12
|
+
# Testing
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.coverage
|
|
15
|
+
htmlcov/
|
|
16
|
+
.mutmut-cache
|
|
17
|
+
.hypothesis/
|
|
18
|
+
|
|
19
|
+
# Tooling caches
|
|
20
|
+
.ruff_cache/
|
|
21
|
+
.ty_cache/
|
|
22
|
+
|
|
23
|
+
# IDE
|
|
24
|
+
.idea/
|
|
25
|
+
.vscode/
|
|
26
|
+
*.swp
|
|
27
|
+
*.swo
|
|
28
|
+
|
|
29
|
+
# OS
|
|
30
|
+
.DS_Store
|
|
31
|
+
Thumbs.db
|
|
32
|
+
|
|
33
|
+
# Project
|
|
34
|
+
logs/
|
|
35
|
+
pytest-of-*/
|
|
36
|
+
.swarm/
|
|
37
|
+
.gemini/
|
|
38
|
+
.geminiignore
|
|
39
|
+
history.log
|
|
40
|
+
refactor_plugin.py
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.15.9
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
args: [--fix, --exit-non-zero-on-fix]
|
|
7
|
+
- id: ruff-format
|
|
8
|
+
|
|
9
|
+
- repo: local
|
|
10
|
+
hooks:
|
|
11
|
+
- id: ty
|
|
12
|
+
name: ty type check
|
|
13
|
+
entry: uv run ty check src/ types/
|
|
14
|
+
language: system
|
|
15
|
+
types: [python]
|
|
16
|
+
pass_filenames: false
|
|
17
|
+
require_serial: true
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
krita_cli-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
krita_cli-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: krita-cli
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: SOTA CLI + MCP server for programmatic painting in Krita
|
|
5
|
+
Project-URL: Homepage, https://github.com/github/krita-cli
|
|
6
|
+
Project-URL: Repository, https://github.com/github/krita-cli
|
|
7
|
+
Project-URL: Issues, https://github.com/github/krita-cli/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/github/krita-cli/blob/master/CHANGELOG.md
|
|
9
|
+
Author: Krita MCP Contributors
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: ai,automation,claude,cli,fastmcp,krita,mcp,painting
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Multimedia :: Graphics :: Editors :: Raster-Based
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
|
+
Requires-Dist: fastmcp>=3.1.0
|
|
23
|
+
Requires-Dist: httpx>=0.28.1
|
|
24
|
+
Requires-Dist: pydantic-settings>=2.0.0
|
|
25
|
+
Requires-Dist: pydantic>=2.12.5
|
|
26
|
+
Requires-Dist: rich>=13.0.0
|
|
27
|
+
Requires-Dist: typer>=0.9.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: beartype>=0.18.0; extra == 'dev'
|
|
30
|
+
Provides-Extra: numpy
|
|
31
|
+
Requires-Dist: numpy>=1.26.0; extra == 'numpy'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# Krita MCP Server & CLI
|
|
35
|
+
|
|
36
|
+
Let AI agents paint in [Krita](https://krita.org/) via the [Model Context Protocol](https://modelcontextprotocol.io/).
|
|
37
|
+
|
|
38
|
+
This subproject provides the core implementation of the Krita-MCP ecosystem, including the FastMCP server, the `krita` CLI, and the high-performance Python plugin.
|
|
39
|
+
|
|
40
|
+
## 🛠️ Components
|
|
41
|
+
|
|
42
|
+
1. **Krita Plugin** (`krita-plugin/`) — A Python plugin for Krita that exposes a thread-safe HTTP server on `localhost:5678`.
|
|
43
|
+
2. **MCP Server** (`src/krita_mcp/`) — A FastMCP server exposing 40+ painting and manipulation tools.
|
|
44
|
+
3. **Krita CLI** (`src/krita_cli/`) — A Typer-based command line interface for human operators.
|
|
45
|
+
4. **Krita Client** (`src/krita_client/`) — A reusable, fully-typed Python library for Krita automation.
|
|
46
|
+
|
|
47
|
+
## 🚀 Setup
|
|
48
|
+
|
|
49
|
+
### 1. Krita Plugin Installation
|
|
50
|
+
Copy the contents of `krita-plugin/` to your Krita resources:
|
|
51
|
+
- **Windows**: `%APPDATA%\krita\pykrita\`
|
|
52
|
+
- **Linux**: `~/.local/share/krita/pykrita/`
|
|
53
|
+
- **macOS**: `~/Library/Application Support/krita/pykrita/`
|
|
54
|
+
|
|
55
|
+
Enable **"Krita MCP Bridge"** in Krita (Configure Krita → Python Plugin Manager) and restart.
|
|
56
|
+
|
|
57
|
+
### 2. Environment Setup
|
|
58
|
+
```bash
|
|
59
|
+
# Install dependencies with uv
|
|
60
|
+
uv sync
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 🔧 CLI Commands
|
|
64
|
+
|
|
65
|
+
The `krita` CLI is grouped into logical subcommands:
|
|
66
|
+
|
|
67
|
+
- **Painting**: `stroke`, `fill`, `clear`, `draw-shape`
|
|
68
|
+
- **Layers**: `layers list`, `layers create`, `layers select`, `layers delete`
|
|
69
|
+
- **Selection**: `selection select-rect`, `selection transform`, `selection save-channel`
|
|
70
|
+
- **Canvas**: `canvas-info`, `current-color`, `current-brush`
|
|
71
|
+
- **Session**: `history`, `replay`, `rollback`, `batch`
|
|
72
|
+
- **System**: `health`, `config`, `capabilities`, `security-status`
|
|
73
|
+
|
|
74
|
+
Run `uv run krita --help` for full details.
|
|
75
|
+
|
|
76
|
+
## 🤖 MCP Server Tools (40 Total)
|
|
77
|
+
|
|
78
|
+
The MCP server exposes a vast range of capabilities to AI agents:
|
|
79
|
+
|
|
80
|
+
| Category | Key Tools |
|
|
81
|
+
|----------|-----------|
|
|
82
|
+
| **Core** | `krita_health`, `krita_new_canvas`, `krita_save`, `krita_open_file` |
|
|
83
|
+
| **Painting** | `krita_stroke`, `krita_fill`, `krita_draw_shape`, `krita_set_color`, `krita_set_brush` |
|
|
84
|
+
| **Selection** | `krita_select_rect`, `krita_select_ellipse`, `krita_select_polygon`, `krita_select_by_color`, `krita_select_by_alpha` |
|
|
85
|
+
| **Selection Ops** | `krita_transform_selection`, `krita_grow_selection`, `krita_combine_selections`, `krita_invert_selection` |
|
|
86
|
+
| **Persistence** | `krita_save_selection`, `krita_load_selection`, `krita_save_selection_channel`, `krita_list_selection_channels` |
|
|
87
|
+
| **Automation** | `krita_batch`, `krita_rollback`, `krita_get_command_history` |
|
|
88
|
+
| **Inspection** | `krita_get_canvas_info`, `krita_get_color_at`, `krita_selection_stats`, `krita_security_status` |
|
|
89
|
+
|
|
90
|
+
## ⚡ Performance
|
|
91
|
+
|
|
92
|
+
The plugin uses **numpy-accelerated** direct pixel manipulation for rendering. This ensures that strokes and shapes are rendered significantly faster than standard Python loops, especially on high-resolution canvases.
|
|
93
|
+
|
|
94
|
+
## 🔒 Security
|
|
95
|
+
|
|
96
|
+
Krita MCP includes a built-in security layer to protect your system:
|
|
97
|
+
- **Path Sanitization**: Restricts file operations to allowed directories.
|
|
98
|
+
- **Resource Limits**: Prevents OOM by limiting max canvas dimensions and layer counts.
|
|
99
|
+
- **Rate Limiting**: Throttles rapid command execution.
|
|
100
|
+
- **Security Tool**: `krita_security_status` allows agents to check active limits.
|
|
101
|
+
|
|
102
|
+
## 📄 License
|
|
103
|
+
MIT
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Krita MCP Server & CLI
|
|
2
|
+
|
|
3
|
+
Let AI agents paint in [Krita](https://krita.org/) via the [Model Context Protocol](https://modelcontextprotocol.io/).
|
|
4
|
+
|
|
5
|
+
This subproject provides the core implementation of the Krita-MCP ecosystem, including the FastMCP server, the `krita` CLI, and the high-performance Python plugin.
|
|
6
|
+
|
|
7
|
+
## 🛠️ Components
|
|
8
|
+
|
|
9
|
+
1. **Krita Plugin** (`krita-plugin/`) — A Python plugin for Krita that exposes a thread-safe HTTP server on `localhost:5678`.
|
|
10
|
+
2. **MCP Server** (`src/krita_mcp/`) — A FastMCP server exposing 40+ painting and manipulation tools.
|
|
11
|
+
3. **Krita CLI** (`src/krita_cli/`) — A Typer-based command line interface for human operators.
|
|
12
|
+
4. **Krita Client** (`src/krita_client/`) — A reusable, fully-typed Python library for Krita automation.
|
|
13
|
+
|
|
14
|
+
## 🚀 Setup
|
|
15
|
+
|
|
16
|
+
### 1. Krita Plugin Installation
|
|
17
|
+
Copy the contents of `krita-plugin/` to your Krita resources:
|
|
18
|
+
- **Windows**: `%APPDATA%\krita\pykrita\`
|
|
19
|
+
- **Linux**: `~/.local/share/krita/pykrita/`
|
|
20
|
+
- **macOS**: `~/Library/Application Support/krita/pykrita/`
|
|
21
|
+
|
|
22
|
+
Enable **"Krita MCP Bridge"** in Krita (Configure Krita → Python Plugin Manager) and restart.
|
|
23
|
+
|
|
24
|
+
### 2. Environment Setup
|
|
25
|
+
```bash
|
|
26
|
+
# Install dependencies with uv
|
|
27
|
+
uv sync
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 🔧 CLI Commands
|
|
31
|
+
|
|
32
|
+
The `krita` CLI is grouped into logical subcommands:
|
|
33
|
+
|
|
34
|
+
- **Painting**: `stroke`, `fill`, `clear`, `draw-shape`
|
|
35
|
+
- **Layers**: `layers list`, `layers create`, `layers select`, `layers delete`
|
|
36
|
+
- **Selection**: `selection select-rect`, `selection transform`, `selection save-channel`
|
|
37
|
+
- **Canvas**: `canvas-info`, `current-color`, `current-brush`
|
|
38
|
+
- **Session**: `history`, `replay`, `rollback`, `batch`
|
|
39
|
+
- **System**: `health`, `config`, `capabilities`, `security-status`
|
|
40
|
+
|
|
41
|
+
Run `uv run krita --help` for full details.
|
|
42
|
+
|
|
43
|
+
## 🤖 MCP Server Tools (40 Total)
|
|
44
|
+
|
|
45
|
+
The MCP server exposes a vast range of capabilities to AI agents:
|
|
46
|
+
|
|
47
|
+
| Category | Key Tools |
|
|
48
|
+
|----------|-----------|
|
|
49
|
+
| **Core** | `krita_health`, `krita_new_canvas`, `krita_save`, `krita_open_file` |
|
|
50
|
+
| **Painting** | `krita_stroke`, `krita_fill`, `krita_draw_shape`, `krita_set_color`, `krita_set_brush` |
|
|
51
|
+
| **Selection** | `krita_select_rect`, `krita_select_ellipse`, `krita_select_polygon`, `krita_select_by_color`, `krita_select_by_alpha` |
|
|
52
|
+
| **Selection Ops** | `krita_transform_selection`, `krita_grow_selection`, `krita_combine_selections`, `krita_invert_selection` |
|
|
53
|
+
| **Persistence** | `krita_save_selection`, `krita_load_selection`, `krita_save_selection_channel`, `krita_list_selection_channels` |
|
|
54
|
+
| **Automation** | `krita_batch`, `krita_rollback`, `krita_get_command_history` |
|
|
55
|
+
| **Inspection** | `krita_get_canvas_info`, `krita_get_color_at`, `krita_selection_stats`, `krita_security_status` |
|
|
56
|
+
|
|
57
|
+
## ⚡ Performance
|
|
58
|
+
|
|
59
|
+
The plugin uses **numpy-accelerated** direct pixel manipulation for rendering. This ensures that strokes and shapes are rendered significantly faster than standard Python loops, especially on high-resolution canvases.
|
|
60
|
+
|
|
61
|
+
## 🔒 Security
|
|
62
|
+
|
|
63
|
+
Krita MCP includes a built-in security layer to protect your system:
|
|
64
|
+
- **Path Sanitization**: Restricts file operations to allowed directories.
|
|
65
|
+
- **Resource Limits**: Prevents OOM by limiting max canvas dimensions and layer counts.
|
|
66
|
+
- **Rate Limiting**: Throttles rapid command execution.
|
|
67
|
+
- **Security Tool**: `krita_security_status` allows agents to check active limits.
|
|
68
|
+
|
|
69
|
+
## 📄 License
|
|
70
|
+
MIT
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Required Repository Secrets
|
|
2
|
+
|
|
3
|
+
The following secrets must be configured in GitHub → Settings → Secrets and variables → Actions:
|
|
4
|
+
|
|
5
|
+
| Secret | Description | How to Create |
|
|
6
|
+
|--------|-------------|---------------|
|
|
7
|
+
| `GH_TOKEN` | GitHub Personal Access Token with `repo` scope | GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens |
|
|
8
|
+
| `PYPI_TOKEN` | PyPI API token for publishing packages | https://pypi.org/manage/account/token/ → Create token |
|
|
9
|
+
|
|
10
|
+
## Creating GH_TOKEN
|
|
11
|
+
|
|
12
|
+
1. Go to https://github.com/settings/tokens
|
|
13
|
+
2. Create a fine-grained token with:
|
|
14
|
+
- Repository access: This repository only
|
|
15
|
+
- Permissions: Contents (read/write), Pull requests (read/write), Workflows (read/write)
|
|
16
|
+
3. Copy the token and add it as `GH_TOKEN` in repo secrets
|
|
17
|
+
|
|
18
|
+
## Creating PYPI_TOKEN
|
|
19
|
+
|
|
20
|
+
1. Go to https://pypi.org/manage/account/
|
|
21
|
+
2. Scroll to "API tokens" section
|
|
22
|
+
3. Click "Add API token"
|
|
23
|
+
4. Set scope to "Entire account" or "Specific project" (if krita-cli exists)
|
|
24
|
+
5. Copy the token and add it as `PYPI_TOKEN` in repo secrets
|
|
25
|
+
|
|
26
|
+
## Verifying Secrets
|
|
27
|
+
|
|
28
|
+
After adding secrets, the CI release workflow will use them automatically when pushing to master with a conventional commit that triggers a release.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Performance benchmarks for krita_client and plugin rendering."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import importlib.util
|
|
6
|
+
import time
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _get_plugin_class() -> type:
|
|
11
|
+
"""Import the plugin module via file path (not a pip-installable package)."""
|
|
12
|
+
plugin_path = Path(__file__).parent.parent / "krita-plugin" / "kritamcp" / "__init__.py"
|
|
13
|
+
spec = importlib.util.spec_from_file_location("kritamcp", plugin_path)
|
|
14
|
+
module = importlib.util.module_from_spec(spec)
|
|
15
|
+
spec.loader.exec_module(module) # type: ignore[union-attr]
|
|
16
|
+
return module.KritaMCPExtension # type: ignore[no-any-return]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def benchmark_stroke_rendering_python() -> float:
|
|
20
|
+
"""Benchmark pure Python stroke rendering."""
|
|
21
|
+
plugin_cls = _get_plugin_class()
|
|
22
|
+
|
|
23
|
+
pixels = bytearray(255 * 255 * 4)
|
|
24
|
+
w, h = 255, 255
|
|
25
|
+
points = [[i * 10, i * 10] for i in range(25)]
|
|
26
|
+
radius = 20
|
|
27
|
+
hardness = 0.5
|
|
28
|
+
opacity = 1.0
|
|
29
|
+
r, g, b = 255, 0, 0
|
|
30
|
+
|
|
31
|
+
start = time.perf_counter()
|
|
32
|
+
plugin_cls._draw_stroke_python(pixels, w, h, points, radius, hardness, opacity, r, g, b)
|
|
33
|
+
return time.perf_counter() - start
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def benchmark_stroke_rendering_numpy() -> float:
|
|
37
|
+
"""Benchmark numpy-accelerated stroke rendering."""
|
|
38
|
+
try:
|
|
39
|
+
import numpy as np # noqa: F401, PLC0415
|
|
40
|
+
except ImportError:
|
|
41
|
+
return 0.0
|
|
42
|
+
|
|
43
|
+
plugin_cls = _get_plugin_class()
|
|
44
|
+
|
|
45
|
+
pixels = bytearray(255 * 255 * 4)
|
|
46
|
+
w, h = 255, 255
|
|
47
|
+
points = [[i * 10, i * 10] for i in range(25)]
|
|
48
|
+
radius = 20
|
|
49
|
+
hardness = 0.5
|
|
50
|
+
opacity = 1.0
|
|
51
|
+
r, g, b = 255, 0, 0
|
|
52
|
+
|
|
53
|
+
start = time.perf_counter()
|
|
54
|
+
plugin_cls._draw_stroke_numpy(pixels, w, h, points, radius, hardness, opacity, r, g, b)
|
|
55
|
+
return time.perf_counter() - start
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
python_time = benchmark_stroke_rendering_python()
|
|
60
|
+
numpy_time = benchmark_stroke_rendering_numpy()
|
|
61
|
+
|
|
62
|
+
print(f"Python stroke rendering: {python_time:.4f}s")
|
|
63
|
+
if numpy_time > 0:
|
|
64
|
+
print(f"Numpy stroke rendering: {numpy_time:.4f}s")
|
|
65
|
+
print(f"Speedup: {python_time / numpy_time:.1f}x")
|
|
66
|
+
else:
|
|
67
|
+
print("Numpy not available — skipping numpy benchmark")
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{% set name = 'krita-cli' %}
|
|
2
|
+
{% set version = '1.0.0' %}
|
|
3
|
+
|
|
4
|
+
package:
|
|
5
|
+
name: {{ name|lower }}
|
|
6
|
+
version: {{ version }}
|
|
7
|
+
|
|
8
|
+
source:
|
|
9
|
+
path: ..
|
|
10
|
+
|
|
11
|
+
build:
|
|
12
|
+
number: 0
|
|
13
|
+
script: {{ PYTHON }} -m pip install . --no-deps -vv
|
|
14
|
+
entry_points:
|
|
15
|
+
- krita = krita_cli.cli:app
|
|
16
|
+
|
|
17
|
+
requirements:
|
|
18
|
+
host:
|
|
19
|
+
- python >=3.12
|
|
20
|
+
- pip
|
|
21
|
+
- hatchling
|
|
22
|
+
run:
|
|
23
|
+
- python >=3.12
|
|
24
|
+
- fastmcp >=3.1.0
|
|
25
|
+
- httpx >=0.28.1
|
|
26
|
+
- pydantic >=2.12.5
|
|
27
|
+
- pydantic-settings >=2.0.0
|
|
28
|
+
- rich >=13.0.0
|
|
29
|
+
- typer >=0.9.0
|
|
30
|
+
|
|
31
|
+
test:
|
|
32
|
+
commands:
|
|
33
|
+
- krita --help
|
|
34
|
+
|
|
35
|
+
about:
|
|
36
|
+
home: https://github.com/edithatogo/krita-cli
|
|
37
|
+
license: MIT
|
|
38
|
+
license_file: LICENSE
|
|
39
|
+
summary: SOTA CLI + MCP server for programmatic painting in Krita
|
|
40
|
+
description: |
|
|
41
|
+
Krita CLI provides a bridge between AI agents, developers, and the Krita desktop application.
|
|
42
|
+
It enables real-time painting, canvas manipulation, and workflow automation.
|
|
43
|
+
dev_url: https://github.com/edithatogo/krita-cli
|
|
44
|
+
doc_url: https://github.com/edithatogo/krita-cli
|
|
45
|
+
|
|
46
|
+
extra:
|
|
47
|
+
recipe-maintainers:
|
|
48
|
+
- edithatogo
|