Imported from dishanagalawatta/SkillManager (
AGENTS.md). Install upstream withnpx skills add dishanagalawatta/SkillManager. Copyright stays with the author.
Agent Instructions
This file defines constraints, conventions, and workflows for AI agents and human contributors working on SkillManager. Keep it concise.
Core Constraints
Exclusions (never modify)
| Path | Reason |
|---|---|
TODO.md |
User-managed task list |
.agents/commands/** |
User-managed agent commands |
.agents/skills/** |
Installed agent skills |
image/TODO/** |
Packaging reference screenshots |
Mandatory Rules
-
Entry point: Always use
uv run python -m skill_manager.__main__for development. -
QML lifecycle: Clear
cacheBufferbefore settingmodel = nullto prevent incubation destruction exceptions. -
Threading: Never block the PySide6 event loop. Heavy work runs on
joblib.ParallelorBackgroundTaskRunner. -
Telemetry: Never log or commit API tokens.
.envis gitignored. -
Git revert: Any
git checkout --,git revert,git reset(hard/mixed), or any other command that discards or reverts changes must be approved by the user first. Tag the user for confirmation before executing. -
UI Validation (REAL APP ONLY — ZERO TOLERANCE): After EVERY change involving layout, positioning, visibility, or text rendering in QML (including debugging/fixing text clipping), you MUST visually verify using
look_aton a screenshot of the REAL running app (uv run skill-manager).EXPLICITLY FORBIDDEN (automatic violation)
- ❌ Writing inline QML (
qml = '''...''') in Python test scripts - ❌ Creating temporary
.qmlfiles under/tmp/or anywhere outsidesrc/skill_manager/SkillManagerComponents/ - ❌ Instantiating
QQmlApplicationEnginein test scripts with ad-hoc QML content - ❌ Using
grabWindow()or any capture method on anything other than the realMain.qmlloaded through the realAppController - ❌ Running UI/rendering tests through pytest (these are for logic/contract testing only)
- ❌ Referencing old/stale screenshot captures from previous verification runs
The ONLY valid verification procedure is: (a) Start the real app via
uv run skill-manager(b) Identify ALL views/panels affected by the change (Library, QuickCopy, etc.) — verify EACH ONE, not just the first one you think of (c) For each affected view: - Navigate to that view - Select a skill that exercises the changed code path - Wait for QML to settle (at least 3s after selectSkill) - Verify QML debug logs (INSPECTOR_DEBUG, LAYOUT_CHAIN) confirm the expected state (d) Capture a screenshot usingPySide6.QtGui.QWindow.grabWindow()from a helper script that shares the same process as the real AppController — do NOT use IPCCommandChannelcapture (grabs wrong region in headless/multiscreen environments) (e) Clean all captures fromdata/mcp/captures/BEFORE each run so no stale screenshot is accidentally re-analyzed (f) Pass the NEW screenshot tolook_atfor analysis (g) CONFIRM the active view in the screenshot matches the expected view (Library vs QuickCopy vs Settings) — if the view is wrong, fix the verification script and retakeCRITICAL: Visual Evidence Overrides Properties: A
look_atanalysis showing clipped/truncated/overflowing text takes ABSOLUTE PRIORITY over any QML property values (contentHeight,contentWidth,implicitHeight, etc.) or debug logging. If the screenshot shows clipping, the fix is INCOMPLETE — do not rationalize away visual evidence with property values. Investigate ALL visual issueslook_atreports, not just the one you were checking.Enforcement: Any violation of this rule triggers IMMEDIATE REVERSION of all unverified QML changes and restart from last known-good state. Do NOT mark any UI/rendering work complete without real-app visual validation evidence.
- ❌ Writing inline QML (
-
Input Injection Safety (ZERO TOLERANCE): Real mouse/keyboard injection (
ydotooluinput,pyautogui, Win32keybd_event/SendInput) sends input to the user's live desktop. It MUST NEVER run from tests, CI, or headless processes, and MCP input tools MUST NEVER inject into a window that is not the live SkillManager GUI.- Single source of truth: ALL injection safety decisions MUST route through
src/skill_manager/utils/input_guard.py—injection_allowed()(env guard: pytest/offscreen) andinjection_refused_reason()(adds GUI-window presence check). Never add a new injection path or guard check anywhere else. - Patch target: Tests that exercise injection code MUST patch
skill_manager.utils.input_guard.*(or the module-level name imported by the caller, e.g.utils.linux.injection_allowed). NEVER patch a platform module by guesswork — the original incident happened because a test patchedwin32.send_paste_to_focused_windowwhile the code dispatched toutils.linuxon non-Windows, so the realydotool key 29+47(Ctrl+V) executed against the live desktop. - No bypass: Never delete/override
PYTEST_CURRENT_TESTorQT_QPA_PLATFORM=offscreento force real injection in a test, and never assert a realsubprocess/keybd_eventcall fired during a pytest run (regression guard:tests/test_linux_utils.py::test_send_ctrl_v_blocked_under_pytest).
- Single source of truth: ALL injection safety decisions MUST route through
Conventions
Code Style
- Lint:
uv run ruff check src tests— must pass before commit - Format:
uv run ruff format src tests— must pass before commit - Type hints: Use
pyrightwith.pyrightconfig.jsonsettings - QML: Follow
Theme.qmlsemantic tokens; no hardcoded colors/sizes
QML UI Conventions
- Ribbons (
GlassPill): Must useLayout.preferredHeight: 48andradius: 24to form a perfect pill. Do not apply external left/right margins directly toGlassPill. - Inner Controls: Elements inside ribbons (e.g.,
TabButton, inner rectangles) should useradius: 20to perfectly contour the outer pill.RowLayoutinside the pill should typically useanchors.margins: 4. - Buttons: Prefer
IconButtonwithsolar:icons over text-heavyActionButtons inside compact ribbons. - Roles: Use
role: "primary-outline"instead of solid filledrole: "primary"for secondary or auxiliary actions to reduce visual weight. - Toggles: Use
IconButtonwith dynamiciconSource(e.g., swapping betweenbold-duotoneandbroken) instead ofGlassToggleButton. - Layouts & Separators: Flatten
RowLayoutgroupings when elements have conditional visibility (visible: condition). Applyvisibleto individual elements instead of wrapper layouts to prevent orphaned separators when elements are hidden. - Accessible roles: Persistent toggles →
Accessible.CheckBox+checkable/checked; mutually-exclusive tabs/views →Accessible.PageTab; momentary buttons keepButton. Every toggle needsonPressAction+onToggleActioncalling the click slot. SeeDESIGN.md§ Accessibility (ADR-0031). - Focus properties:
visualFocus/hoveredareControl/HoverHandler-only. OnItem/Rectangle/MouseAreauseactiveFocus/containsMouse—visualFocuson anItemisundefinedand fails the QML diagnostic suite. - Accessible names: Never empty — fallback
tooltipText || iconText || labelText || text. Tooltips must surface on keyboard focus, not hover alone.
Testing
- Framework: pytest + pytest-qt + pytest-cov
- Parallel:
uv run pytest -n auto --dist loadfile - Coverage: Target 80% (
fail_under = 80inpyproject.toml) - Run all checks:
python scripts/dev_test.py
Git & Commits
- Use Conventional Commits format
- Prefix:
feat:,fix:,refactor:,test:,chore:,docs: - Keep subject line ≤ 50 characters
- Body only when "why" isn't obvious from subject
- Release tokens: Commits on
mainmay carry opt-in tokens[patch],[minor],[major],[dev]matched as substrings in the subject or body.[dev]publishes a prerelease (x.y.z-dev.n); a[patch]while a dev line is active promotes it to stable. Never write a bracketed token word in body prose — e.g. "promotion via[patch]" in a[dev]commit body overrides the subject token and releases stable instead.
Documentation & Architecture Diagrams
- Visual Diagrams Required: Any major feature, architecture change, distribution/installer lifecycle, or user workflow MUST include clear Mermaid diagrams (
flowchart,sequenceDiagram, etc.) in relevant docs (docs/ARCHITECTURE.md,docs/INSTALL.md,docs/RELEASING.md) to ensure immediate visual clarity for end users and maintainers.
Workflow
Before Any Edit
- Run
uv run ruff check src teststo verify baseline - Check
docs/HOUSEKEEPING.mdfor cleanup rules - Review related ADRs in
docs/adr/if changing architecture
After Any Edit
- Run
uv run ruff check src tests --fix - Run
uv run ruff format src tests - Run
uv run pytest tests/test_<relevant>.py(smoke subset) - Verify
git statusshows no unexpected untracked files
Conductor Tracks
- Active tracks live in
conductor/tracks/<name>/ - Each track has
metadata.json,plan.md, and optionallyspec.md - When a track is fully merged, archive it to
conductor/_archive/<date>/ - See
conductor/workflow.mdfor full lifecycle
ADR Process
- New architectural decisions → create
docs/adr/ADR-XXXX-<slug>.md - Update
ADR_INDEX.mdwith entry - See
docs/adr/0000-template.mdfor format
Forbidden Actions
- Never commit
.env,data/*.json, orsrc/data/*.json - Never modify
TODO.md,.agents/commands/,.agents/skills/ - Never hardcode colors, sizes, or fonts in QML (use
Theme.qmltokens) - Never use
ThreadPoolExecutorfor heavy work (usejoblib.Parallel) - Never block the main thread with I/O or computation
Quick Reference
| Task | Command |
|---|---|
| Run app | uv run skill-manager |
| Lint | uv run ruff check src tests |
| Lint (single file) | uv run ruff check <path> |
| Format | uv run ruff format src tests |
| Format (single file) | uv run ruff format <path> |
| Type check | uv run pyright src/ |
| Test (parallel) | uv run pytest -n auto |
| Test (single file) | uv run pytest tests/test_config.py |
| All checks | python scripts/dev_test.py |
| Build | uv run skill-manager-build |
| MCP server (read) | uv run skill-manager --mcp |
| MCP server (write) | uv run skill-manager --mcp --mcp-allow-write |
Cross-references
-
docs/HOUSEKEEPING.md— cleanup rules -
conductor/workflow.md— track lifecycle -
docs/CONTRIBUTING.md— contribution guidelines -
ADR_INDEX.md— architecture decisions -
UI Validation: See Mandatory Rule #6 — applies to every QML layout/positioning/rendering change.