norns-ide 0.0.2__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 (147) hide show
  1. norns_ide-0.0.2/LICENSE +21 -0
  2. norns_ide-0.0.2/MANIFEST.in +10 -0
  3. norns_ide-0.0.2/PKG-INFO +196 -0
  4. norns_ide-0.0.2/README.md +159 -0
  5. norns_ide-0.0.2/backend/__init__.py +1 -0
  6. norns_ide-0.0.2/backend/app/__init__.py +1 -0
  7. norns_ide-0.0.2/backend/app/agents/__init__.py +3 -0
  8. norns_ide-0.0.2/backend/app/agents/runner.py +637 -0
  9. norns_ide-0.0.2/backend/app/api/__init__.py +3 -0
  10. norns_ide-0.0.2/backend/app/api/auth.py +88 -0
  11. norns_ide-0.0.2/backend/app/api/boards.py +626 -0
  12. norns_ide-0.0.2/backend/app/api/cards.py +220 -0
  13. norns_ide-0.0.2/backend/app/api/connectors.py +153 -0
  14. norns_ide-0.0.2/backend/app/api/plugins.py +21 -0
  15. norns_ide-0.0.2/backend/app/api/router.py +68 -0
  16. norns_ide-0.0.2/backend/app/card_preview.py +34 -0
  17. norns_ide-0.0.2/backend/app/config.py +88 -0
  18. norns_ide-0.0.2/backend/app/connector_config.py +442 -0
  19. norns_ide-0.0.2/backend/app/cursor_api.py +142 -0
  20. norns_ide-0.0.2/backend/app/database.py +134 -0
  21. norns_ide-0.0.2/backend/app/faults.py +40 -0
  22. norns_ide-0.0.2/backend/app/main.py +52 -0
  23. norns_ide-0.0.2/backend/app/models/__init__.py +15 -0
  24. norns_ide-0.0.2/backend/app/models/board.py +89 -0
  25. norns_ide-0.0.2/backend/app/models/card.py +73 -0
  26. norns_ide-0.0.2/backend/app/models/connector.py +66 -0
  27. norns_ide-0.0.2/backend/app/orchestrator/__init__.py +3 -0
  28. norns_ide-0.0.2/backend/app/orchestrator/enqueue.py +60 -0
  29. norns_ide-0.0.2/backend/app/orchestrator/gates.py +273 -0
  30. norns_ide-0.0.2/backend/app/orchestrator/progression.py +139 -0
  31. norns_ide-0.0.2/backend/app/orchestrator/recovery.py +32 -0
  32. norns_ide-0.0.2/backend/app/orchestrator/split.py +254 -0
  33. norns_ide-0.0.2/backend/app/orchestrator/state_machine.py +100 -0
  34. norns_ide-0.0.2/backend/app/plantuml/__init__.py +3 -0
  35. norns_ide-0.0.2/backend/app/plantuml/renderer.py +94 -0
  36. norns_ide-0.0.2/backend/app/plugins/__init__.py +11 -0
  37. norns_ide-0.0.2/backend/app/plugins/adapters.py +139 -0
  38. norns_ide-0.0.2/backend/app/plugins/base.py +82 -0
  39. norns_ide-0.0.2/backend/app/plugins/catalog.py +246 -0
  40. norns_ide-0.0.2/backend/app/plugins/mcp_protocol.py +173 -0
  41. norns_ide-0.0.2/backend/app/plugins/norns.py +589 -0
  42. norns_ide-0.0.2/backend/app/plugins/tool_policy.py +23 -0
  43. norns_ide-0.0.2/backend/app/tools/__init__.py +3 -0
  44. norns_ide-0.0.2/backend/app/tools/github.py +239 -0
  45. norns_ide-0.0.2/backend/app/tools/jira.py +283 -0
  46. norns_ide-0.0.2/backend/app/tools/polarion.py +433 -0
  47. norns_ide-0.0.2/backend/app/tools/registry.py +86 -0
  48. norns_ide-0.0.2/backend/app/ui_assets.py +92 -0
  49. norns_ide-0.0.2/backend/app/workspace.py +135 -0
  50. norns_ide-0.0.2/backend/tests/__init__.py +1 -0
  51. norns_ide-0.0.2/backend/tests/conftest.py +10 -0
  52. norns_ide-0.0.2/backend/tests/test_api.py +473 -0
  53. norns_ide-0.0.2/backend/tests/test_card_preview.py +48 -0
  54. norns_ide-0.0.2/backend/tests/test_config.py +63 -0
  55. norns_ide-0.0.2/backend/tests/test_connectors.py +157 -0
  56. norns_ide-0.0.2/backend/tests/test_cursor_api.py +229 -0
  57. norns_ide-0.0.2/backend/tests/test_database.py +176 -0
  58. norns_ide-0.0.2/backend/tests/test_faults.py +135 -0
  59. norns_ide-0.0.2/backend/tests/test_handoff.py +54 -0
  60. norns_ide-0.0.2/backend/tests/test_norns_cli.py +97 -0
  61. norns_ide-0.0.2/backend/tests/test_orchestrator.py +409 -0
  62. norns_ide-0.0.2/backend/tests/test_packaged_ui_matches_compose.py +127 -0
  63. norns_ide-0.0.2/backend/tests/test_packaging.py +215 -0
  64. norns_ide-0.0.2/backend/tests/test_pending_writes.py +215 -0
  65. norns_ide-0.0.2/backend/tests/test_plugins.py +410 -0
  66. norns_ide-0.0.2/backend/tests/test_polarion.py +152 -0
  67. norns_ide-0.0.2/backend/tests/test_progression.py +186 -0
  68. norns_ide-0.0.2/backend/tests/test_recovery.py +45 -0
  69. norns_ide-0.0.2/backend/tests/test_registry.py +23 -0
  70. norns_ide-0.0.2/backend/tests/test_runner.py +464 -0
  71. norns_ide-0.0.2/backend/tests/test_state_machine.py +67 -0
  72. norns_ide-0.0.2/backend/tests/test_tool_policy.py +16 -0
  73. norns_ide-0.0.2/backend/tests/test_ui_assets.py +40 -0
  74. norns_ide-0.0.2/backend/tests/test_workspace.py +75 -0
  75. norns_ide-0.0.2/frontend/.prettierignore +8 -0
  76. norns_ide-0.0.2/frontend/.prettierrc.json +8 -0
  77. norns_ide-0.0.2/frontend/dist/assets/index-BhxA4RYX.css +1 -0
  78. norns_ide-0.0.2/frontend/dist/assets/index-DTPm_GI-.js +71 -0
  79. norns_ide-0.0.2/frontend/dist/index.html +17 -0
  80. norns_ide-0.0.2/frontend/eslint.config.js +29 -0
  81. norns_ide-0.0.2/frontend/index.html +16 -0
  82. norns_ide-0.0.2/frontend/package-lock.json +3880 -0
  83. norns_ide-0.0.2/frontend/package.json +30 -0
  84. norns_ide-0.0.2/frontend/src/App.tsx +156 -0
  85. norns_ide-0.0.2/frontend/src/api/client.ts +30 -0
  86. norns_ide-0.0.2/frontend/src/boardLayout.test.ts +26 -0
  87. norns_ide-0.0.2/frontend/src/boardLayout.ts +19 -0
  88. norns_ide-0.0.2/frontend/src/cardJourney.test.ts +180 -0
  89. norns_ide-0.0.2/frontend/src/cardJourney.ts +195 -0
  90. norns_ide-0.0.2/frontend/src/cardPreview.test.ts +57 -0
  91. norns_ide-0.0.2/frontend/src/cardPreview.ts +107 -0
  92. norns_ide-0.0.2/frontend/src/components/AgentConfig.tsx +304 -0
  93. norns_ide-0.0.2/frontend/src/components/Board.tsx +261 -0
  94. norns_ide-0.0.2/frontend/src/components/CardDrawer.tsx +420 -0
  95. norns_ide-0.0.2/frontend/src/components/CardHistory.tsx +180 -0
  96. norns_ide-0.0.2/frontend/src/components/CardItem.tsx +34 -0
  97. norns_ide-0.0.2/frontend/src/components/Column.tsx +112 -0
  98. norns_ide-0.0.2/frontend/src/components/ConnectorHealth.tsx +510 -0
  99. norns_ide-0.0.2/frontend/src/components/Dialog.tsx +101 -0
  100. norns_ide-0.0.2/frontend/src/components/LoginForm.tsx +53 -0
  101. norns_ide-0.0.2/frontend/src/components/MarkdownPreview.tsx +82 -0
  102. norns_ide-0.0.2/frontend/src/components/Settings.tsx +77 -0
  103. norns_ide-0.0.2/frontend/src/components/StateMachineEditor.tsx +866 -0
  104. norns_ide-0.0.2/frontend/src/components/WaitLive.tsx +52 -0
  105. norns_ide-0.0.2/frontend/src/gateLabels.test.ts +79 -0
  106. norns_ide-0.0.2/frontend/src/gateLabels.ts +101 -0
  107. norns_ide-0.0.2/frontend/src/main.tsx +16 -0
  108. norns_ide-0.0.2/frontend/src/markdown.test.ts +55 -0
  109. norns_ide-0.0.2/frontend/src/runHints.test.ts +24 -0
  110. norns_ide-0.0.2/frontend/src/runHints.ts +20 -0
  111. norns_ide-0.0.2/frontend/src/status.ts +11 -0
  112. norns_ide-0.0.2/frontend/src/styles/control-room.css +1545 -0
  113. norns_ide-0.0.2/frontend/src/types/index.ts +94 -0
  114. norns_ide-0.0.2/frontend/src/waitProgress.test.ts +21 -0
  115. norns_ide-0.0.2/frontend/src/waitProgress.ts +42 -0
  116. norns_ide-0.0.2/frontend/src/workspaceLabel.test.ts +20 -0
  117. norns_ide-0.0.2/frontend/src/workspaceLabel.ts +23 -0
  118. norns_ide-0.0.2/frontend/style-lab.css +731 -0
  119. norns_ide-0.0.2/frontend/style-lab.html +33 -0
  120. norns_ide-0.0.2/frontend/style-lab.js +378 -0
  121. norns_ide-0.0.2/frontend/tsconfig.json +21 -0
  122. norns_ide-0.0.2/frontend/vite.config.ts +16 -0
  123. norns_ide-0.0.2/norns/__init__.py +3 -0
  124. norns_ide-0.0.2/norns/__main__.py +4 -0
  125. norns_ide-0.0.2/norns/cli.py +90 -0
  126. norns_ide-0.0.2/norns/desktop.py +167 -0
  127. norns_ide-0.0.2/norns/electron/main.js +27 -0
  128. norns_ide-0.0.2/norns/electron/package-lock.json +801 -0
  129. norns_ide-0.0.2/norns/electron/package.json +13 -0
  130. norns_ide-0.0.2/norns/home.py +122 -0
  131. norns_ide-0.0.2/norns/mcp.py +31 -0
  132. norns_ide-0.0.2/norns/web/assets/index-BhxA4RYX.css +1 -0
  133. norns_ide-0.0.2/norns/web/assets/index-DTPm_GI-.js +71 -0
  134. norns_ide-0.0.2/norns/web/index.html +17 -0
  135. norns_ide-0.0.2/norns_build.py +230 -0
  136. norns_ide-0.0.2/norns_ide.egg-info/PKG-INFO +196 -0
  137. norns_ide-0.0.2/norns_ide.egg-info/SOURCES.txt +145 -0
  138. norns_ide-0.0.2/norns_ide.egg-info/dependency_links.txt +1 -0
  139. norns_ide-0.0.2/norns_ide.egg-info/entry_points.txt +8 -0
  140. norns_ide-0.0.2/norns_ide.egg-info/requires.txt +24 -0
  141. norns_ide-0.0.2/norns_ide.egg-info/top_level.txt +4 -0
  142. norns_ide-0.0.2/pyproject.toml +92 -0
  143. norns_ide-0.0.2/scripts/stage-ui.sh +13 -0
  144. norns_ide-0.0.2/setup.cfg +4 -0
  145. norns_ide-0.0.2/worker/__init__.py +1 -0
  146. norns_ide-0.0.2/worker/main.py +14 -0
  147. norns_ide-0.0.2/worker/tasks.py +8 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 YanChao1999
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.
@@ -0,0 +1,10 @@
1
+ include norns_build.py
2
+ recursive-include norns/web *
3
+ include norns/electron/main.js
4
+ include norns/electron/package.json
5
+ include norns/electron/package-lock.json
6
+ include scripts/stage-ui.sh
7
+ graft frontend
8
+ prune frontend/node_modules
9
+ global-exclude __pycache__
10
+ global-exclude *.pyc
@@ -0,0 +1,196 @@
1
+ Metadata-Version: 2.4
2
+ Name: norns-ide
3
+ Version: 0.0.2
4
+ Summary: Kanban orchestration system with per-column LLM agents and human approval gates
5
+ Author: YanChao1999
6
+ License: MIT
7
+ Project-URL: Homepage, https://yanchao1999.github.io/Norns/
8
+ Project-URL: Repository, https://github.com/YanChao1999/Norns
9
+ Project-URL: Issues, https://github.com/YanChao1999/Norns/issues
10
+ Requires-Python: >=3.12
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: fastapi>=0.115.0
14
+ Requires-Dist: uvicorn[standard]>=0.30.0
15
+ Requires-Dist: sqlalchemy[asyncio]>=2.0.32
16
+ Requires-Dist: asyncpg>=0.29.0
17
+ Requires-Dist: aiosqlite>=0.20.0
18
+ Requires-Dist: arq>=0.26.0
19
+ Requires-Dist: openai>=1.40.0
20
+ Requires-Dist: PyGithub>=2.3.0
21
+ Requires-Dist: jira>=3.8.0
22
+ Requires-Dist: polarion>=1.0.0
23
+ Requires-Dist: cryptography>=43.0.0
24
+ Requires-Dist: itsdangerous>=2.2.0
25
+ Requires-Dist: pydantic-settings>=2.4.0
26
+ Requires-Dist: httpx>=0.27.0
27
+ Requires-Dist: plantuml>=0.3.0
28
+ Requires-Dist: cursor-sdk>=1.0.28
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=8.3.0; extra == "dev"
31
+ Requires-Dist: pytest-asyncio>=0.23.8; extra == "dev"
32
+ Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
33
+ Requires-Dist: ruff>=0.8.0; extra == "dev"
34
+ Requires-Dist: build>=1.2.0; extra == "dev"
35
+ Requires-Dist: twine>=6.0.0; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # Norns
39
+
40
+ Norns is a Kanban orchestration system where each board column runs an isolated LLM agent and a human approval gate controls progression to the next stage. The name comes from the Norse Norns: Urd, Verdandi, and Skuld.
41
+
42
+ **v0.0.2** site: [yanchao1999.github.io/Norns](https://yanchao1999.github.io/Norns/). First-use backlog: [ROADMAP.md](ROADMAP.md).
43
+
44
+ ## Features
45
+ - Local Control Room (`norns init` / `norns run`) — UI in the browser by default, optional Electron window, config under `~/.norns`
46
+ - Visual state machine editor for board stages, order, parallel tracks, and human-gate vs auto-advance
47
+ - FastAPI + async SQLAlchemy backend with PostgreSQL-ready configuration
48
+ - ARQ/Redis queue for isolated stage execution (optional; local IDE runs stages in-process)
49
+ - React + TypeScript Kanban UI with approval-aware movement
50
+ - Stage agents may recommend **approve** or **reject**; a human still confirms at the gate
51
+ - Encrypted connector secrets at rest with Fernet
52
+ - OpenAI-compatible stage agents with explicit per-stage tool allowlists
53
+ - PlantUML-first documentation and handoff previews
54
+
55
+ ## Flow Diagram
56
+ ```plantuml
57
+ @startuml
58
+ skinparam monochrome true
59
+ actor Human
60
+ rectangle Board {
61
+ rectangle "Stage 1\n(Urd agent)" as S1
62
+ rectangle "Stage 2\n(Verdandi agent)" as S2
63
+ rectangle "Stage 3\n(Skuld agent)" as S3
64
+ }
65
+ Human --> S1 : create / approve
66
+ S1 --> Human : handoff + recommend approve/reject
67
+ Human --> S2 : confirm approve or reject
68
+ S2 --> Human : handoff + recommend approve/reject
69
+ Human --> S3 : confirm approve or reject
70
+ @enduml
71
+ ```
72
+
73
+ ## Runtime Sequence
74
+ ```plantuml
75
+ @startuml
76
+ skinparam monochrome true
77
+ actor Human
78
+ participant Frontend
79
+ participant Backend
80
+ participant Redis
81
+ participant Worker
82
+ participant Agent
83
+
84
+ Human -> Frontend : Approve card
85
+ Frontend -> Backend : POST /api/cards/{id}/approve
86
+ Backend -> Redis : enqueue next stage
87
+ Redis -> Worker : run_stage_task
88
+ Worker -> Agent : run_stage(card, stage, run)
89
+ Agent -> Backend : persist AgentRun + handoff (recommendation is advisory)
90
+ Backend -> Frontend : waiting_approval state
91
+ Human -> Frontend : confirm approve or reject
92
+ @enduml
93
+ ```
94
+
95
+ ## Architecture Overview
96
+ - **Boards / Stages** define the workflow and per-column agent configuration. Edit stages and **transition lines** in the Control Room **Machine** view. Two default lines from one stage **split** the card into parallel tracks (for example unit tests and software). Lines from two or more stages into one stage **join** those tracks when every track has finished.
97
+ - **Cards** carry the work item body and current stage pointer.
98
+ - **Agent runs** are isolated; no chat memory is shared between stages.
99
+ - **Handoffs** from stage _N_ are the only structured context for stage _N+1_. On a human gate, the agent may set `recommendation` to `approve` or `reject`; the card still waits until a person confirms. Draw an If on `recommendation` if that suggestion should choose the next stage after confirmation.
100
+ - **Connectors** are Python-library backed only (PyGithub, jira, polarion); raw credentials are never exposed to agents.
101
+
102
+ ## Install (pip / uv)
103
+
104
+ Python 3.12+. `norns run` opens the Control Room in your browser. Electron is optional.
105
+
106
+ ```bash
107
+ # From this checkout (needs Node.js 20+ or Docker once, to compile the UI into the package):
108
+ uv tool install .
109
+ # or
110
+ python3 -m pip install .
111
+
112
+ norns init # prints an admin password; also stored in ~/.norns/config.toml
113
+ norns run # http://127.0.0.1:8765
114
+ ```
115
+
116
+ After this is published (see [PUBLISH.md](PUBLISH.md)):
117
+
118
+ ```bash
119
+ uv tool install norns-ide
120
+ # or
121
+ python3 -m pip install norns-ide
122
+ ```
123
+
124
+ The PyPI name is `norns-ide` because [`norns`](https://pypi.org/project/norns/) is already taken. The command is still `norns`.
125
+
126
+ From GitHub after this branch is merged:
127
+
128
+ ```bash
129
+ uv tool install git+https://github.com/YanChao1999/Norns.git
130
+ # or
131
+ python3 -m pip install git+https://github.com/YanChao1999/Norns.git
132
+ ```
133
+
134
+ `norns run --no-window` starts the server without opening a browser (used by CI). Data lives under `~/.norns` unless you pass `--home` or set `NORNS_HOME`. Use `norns init --force` to replace config and delete `norns.db` (no schema back-compat before a published 0.0.1). Set `openai.api_key` in `~/.norns/config.toml` when you want a real model instead of a placeholder handoff.
135
+
136
+ ### Optional desktop window
137
+
138
+ ```bash
139
+ npm install --prefix norns/electron # from a git checkout
140
+ norns run
141
+ ```
142
+
143
+ ### Developer checkout
144
+
145
+ `uv run` is an editable install, so it does not run the wheel build that bakes the UI in. `norns run` compiles `frontend/` on first start with npm if it is on PATH (or `./.tools/node`), otherwise with Docker using the same `node:20` image as `docker compose up`. If docker compose left `frontend/node_modules` root-owned, the build uses `~/.cache/norns/ui-build` instead. Rebuild after UI source changes with `./scripts/stage-ui.sh` (same npm-or-Docker path; it always rebuilds, unlike `norns run`).
146
+
147
+ ```bash
148
+ uv sync
149
+ uv run norns init
150
+ uv run norns run
151
+ ```
152
+
153
+ ## Docker compose (optional)
154
+ Use this when you want PostgreSQL, Redis, and a browser-based Vite dev server instead of the desktop IDE.
155
+
156
+ 1. Copy `.env.example` to `.env` and set real secrets.
157
+ 2. Generate unique secrets (do not keep the example values):
158
+ ```bash
159
+ python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
160
+ python -c "import secrets; print(secrets.token_urlsafe(32))"
161
+ ```
162
+ Put them in `ENCRYPTION_KEY` and `SECRET_KEY`. The API and worker must share the same encryption key.
163
+ 3. Start the stack:
164
+ ```bash
165
+ docker compose up
166
+ ```
167
+ 4. Open:
168
+ - Frontend: `http://localhost:5173`
169
+ - Backend API: `http://localhost:8000/docs`
170
+ 5. Sign in with the `ADMIN_USERNAME` / `ADMIN_PASSWORD` from your `.env` (defaults are `admin` / `admin` only when `NORNS_ENV=local`). For a shared host set `NORNS_ENV=production`, a unique `ADMIN_PASSWORD`, and `SESSION_COOKIE_SECURE=true`.
171
+ 6. Create a board, add a card, open it, and click **Run this stage**. Cards only move after approval unless a stage has auto-advance enabled.
172
+
173
+ `docker compose` builds a Python image once. Rebuild after dependency changes: `docker compose build`.
174
+
175
+ ## Development Setup
176
+ ```bash
177
+ pip install -e ".[dev]"
178
+ python -m pytest backend/tests/ -q
179
+ bash scripts/lint.sh
180
+ cd frontend && npm install && npm run dev
181
+ ```
182
+
183
+ Pull requests to `main` must pass the **CI** GitHub Actions check (`backend` tests, `frontend` typecheck/build, `lint` static analysis and format, `package` wheel/sdist plus `norns` CLI). Direct pushes to `main` are not blocked, but merges are.
184
+
185
+ ## Notes
186
+ - Local IDE mode uses SQLite and `QUEUE_BACKEND=inline` (no Redis). Docker/production can keep Redis via `QUEUE_BACKEND=redis`.
187
+ - Schema is created with SQLAlchemy `create_all`. There is no upgrade migration until 0.0.1 is published; `norns init --force` deletes the local database.
188
+ - Use PostgreSQL in normal deployments via `DATABASE_URL`.
189
+ - Redis backs ARQ worker execution.
190
+ - PlantUML/Kroki rendering is opt-in via `PLANTUML_URL` / `KROKI_URL` (unset means no public egress).
191
+ - An empty per-stage tool allowlist grants **no** tools. Enable **norns** (create cards, edit stages/prompts, edit the state machine, inspect the git workspace), **github**, **jira**, or **polarion** on the column **Agent** dialog. Cursor stages receive those as MCP servers; OpenAI/DeepSeek stages use the same plugins as chat tools.
192
+ - **Workspace (git repo):** each board has a checkout path and/or `https://github.com/org/repo`. Stage agents inherit the board repo; a column **Agent** can override with its own path/URL. Cursor stages then run in that checkout (local agent) instead of a throwaway `/tmp` directory; GitHub tools default to that repo. If neither board nor agent is set, Norns uses the git root of the process working directory.
193
+ - Extra MCP servers: add an **MCP** connector in Settings (stdio command or HTTP URL), then enable it under Agent → Tools. Third-party Python plugins register the `norns.plugins` entry point.
194
+ - `norns mcp --plugins norns,github,jira` runs the plugin MCP server on stdin/stdout (Cursor attaches this automatically when those tools are enabled).
195
+ - `PUT /api/cards/{id}` updates title/body only; new cards always start on the first stage.
196
+ - Change `SECRET_KEY` and `ADMIN_PASSWORD` before any shared deployment. Sessions expire after 8 hours.
@@ -0,0 +1,159 @@
1
+ # Norns
2
+
3
+ Norns is a Kanban orchestration system where each board column runs an isolated LLM agent and a human approval gate controls progression to the next stage. The name comes from the Norse Norns: Urd, Verdandi, and Skuld.
4
+
5
+ **v0.0.2** site: [yanchao1999.github.io/Norns](https://yanchao1999.github.io/Norns/). First-use backlog: [ROADMAP.md](ROADMAP.md).
6
+
7
+ ## Features
8
+ - Local Control Room (`norns init` / `norns run`) — UI in the browser by default, optional Electron window, config under `~/.norns`
9
+ - Visual state machine editor for board stages, order, parallel tracks, and human-gate vs auto-advance
10
+ - FastAPI + async SQLAlchemy backend with PostgreSQL-ready configuration
11
+ - ARQ/Redis queue for isolated stage execution (optional; local IDE runs stages in-process)
12
+ - React + TypeScript Kanban UI with approval-aware movement
13
+ - Stage agents may recommend **approve** or **reject**; a human still confirms at the gate
14
+ - Encrypted connector secrets at rest with Fernet
15
+ - OpenAI-compatible stage agents with explicit per-stage tool allowlists
16
+ - PlantUML-first documentation and handoff previews
17
+
18
+ ## Flow Diagram
19
+ ```plantuml
20
+ @startuml
21
+ skinparam monochrome true
22
+ actor Human
23
+ rectangle Board {
24
+ rectangle "Stage 1\n(Urd agent)" as S1
25
+ rectangle "Stage 2\n(Verdandi agent)" as S2
26
+ rectangle "Stage 3\n(Skuld agent)" as S3
27
+ }
28
+ Human --> S1 : create / approve
29
+ S1 --> Human : handoff + recommend approve/reject
30
+ Human --> S2 : confirm approve or reject
31
+ S2 --> Human : handoff + recommend approve/reject
32
+ Human --> S3 : confirm approve or reject
33
+ @enduml
34
+ ```
35
+
36
+ ## Runtime Sequence
37
+ ```plantuml
38
+ @startuml
39
+ skinparam monochrome true
40
+ actor Human
41
+ participant Frontend
42
+ participant Backend
43
+ participant Redis
44
+ participant Worker
45
+ participant Agent
46
+
47
+ Human -> Frontend : Approve card
48
+ Frontend -> Backend : POST /api/cards/{id}/approve
49
+ Backend -> Redis : enqueue next stage
50
+ Redis -> Worker : run_stage_task
51
+ Worker -> Agent : run_stage(card, stage, run)
52
+ Agent -> Backend : persist AgentRun + handoff (recommendation is advisory)
53
+ Backend -> Frontend : waiting_approval state
54
+ Human -> Frontend : confirm approve or reject
55
+ @enduml
56
+ ```
57
+
58
+ ## Architecture Overview
59
+ - **Boards / Stages** define the workflow and per-column agent configuration. Edit stages and **transition lines** in the Control Room **Machine** view. Two default lines from one stage **split** the card into parallel tracks (for example unit tests and software). Lines from two or more stages into one stage **join** those tracks when every track has finished.
60
+ - **Cards** carry the work item body and current stage pointer.
61
+ - **Agent runs** are isolated; no chat memory is shared between stages.
62
+ - **Handoffs** from stage _N_ are the only structured context for stage _N+1_. On a human gate, the agent may set `recommendation` to `approve` or `reject`; the card still waits until a person confirms. Draw an If on `recommendation` if that suggestion should choose the next stage after confirmation.
63
+ - **Connectors** are Python-library backed only (PyGithub, jira, polarion); raw credentials are never exposed to agents.
64
+
65
+ ## Install (pip / uv)
66
+
67
+ Python 3.12+. `norns run` opens the Control Room in your browser. Electron is optional.
68
+
69
+ ```bash
70
+ # From this checkout (needs Node.js 20+ or Docker once, to compile the UI into the package):
71
+ uv tool install .
72
+ # or
73
+ python3 -m pip install .
74
+
75
+ norns init # prints an admin password; also stored in ~/.norns/config.toml
76
+ norns run # http://127.0.0.1:8765
77
+ ```
78
+
79
+ After this is published (see [PUBLISH.md](PUBLISH.md)):
80
+
81
+ ```bash
82
+ uv tool install norns-ide
83
+ # or
84
+ python3 -m pip install norns-ide
85
+ ```
86
+
87
+ The PyPI name is `norns-ide` because [`norns`](https://pypi.org/project/norns/) is already taken. The command is still `norns`.
88
+
89
+ From GitHub after this branch is merged:
90
+
91
+ ```bash
92
+ uv tool install git+https://github.com/YanChao1999/Norns.git
93
+ # or
94
+ python3 -m pip install git+https://github.com/YanChao1999/Norns.git
95
+ ```
96
+
97
+ `norns run --no-window` starts the server without opening a browser (used by CI). Data lives under `~/.norns` unless you pass `--home` or set `NORNS_HOME`. Use `norns init --force` to replace config and delete `norns.db` (no schema back-compat before a published 0.0.1). Set `openai.api_key` in `~/.norns/config.toml` when you want a real model instead of a placeholder handoff.
98
+
99
+ ### Optional desktop window
100
+
101
+ ```bash
102
+ npm install --prefix norns/electron # from a git checkout
103
+ norns run
104
+ ```
105
+
106
+ ### Developer checkout
107
+
108
+ `uv run` is an editable install, so it does not run the wheel build that bakes the UI in. `norns run` compiles `frontend/` on first start with npm if it is on PATH (or `./.tools/node`), otherwise with Docker using the same `node:20` image as `docker compose up`. If docker compose left `frontend/node_modules` root-owned, the build uses `~/.cache/norns/ui-build` instead. Rebuild after UI source changes with `./scripts/stage-ui.sh` (same npm-or-Docker path; it always rebuilds, unlike `norns run`).
109
+
110
+ ```bash
111
+ uv sync
112
+ uv run norns init
113
+ uv run norns run
114
+ ```
115
+
116
+ ## Docker compose (optional)
117
+ Use this when you want PostgreSQL, Redis, and a browser-based Vite dev server instead of the desktop IDE.
118
+
119
+ 1. Copy `.env.example` to `.env` and set real secrets.
120
+ 2. Generate unique secrets (do not keep the example values):
121
+ ```bash
122
+ python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
123
+ python -c "import secrets; print(secrets.token_urlsafe(32))"
124
+ ```
125
+ Put them in `ENCRYPTION_KEY` and `SECRET_KEY`. The API and worker must share the same encryption key.
126
+ 3. Start the stack:
127
+ ```bash
128
+ docker compose up
129
+ ```
130
+ 4. Open:
131
+ - Frontend: `http://localhost:5173`
132
+ - Backend API: `http://localhost:8000/docs`
133
+ 5. Sign in with the `ADMIN_USERNAME` / `ADMIN_PASSWORD` from your `.env` (defaults are `admin` / `admin` only when `NORNS_ENV=local`). For a shared host set `NORNS_ENV=production`, a unique `ADMIN_PASSWORD`, and `SESSION_COOKIE_SECURE=true`.
134
+ 6. Create a board, add a card, open it, and click **Run this stage**. Cards only move after approval unless a stage has auto-advance enabled.
135
+
136
+ `docker compose` builds a Python image once. Rebuild after dependency changes: `docker compose build`.
137
+
138
+ ## Development Setup
139
+ ```bash
140
+ pip install -e ".[dev]"
141
+ python -m pytest backend/tests/ -q
142
+ bash scripts/lint.sh
143
+ cd frontend && npm install && npm run dev
144
+ ```
145
+
146
+ Pull requests to `main` must pass the **CI** GitHub Actions check (`backend` tests, `frontend` typecheck/build, `lint` static analysis and format, `package` wheel/sdist plus `norns` CLI). Direct pushes to `main` are not blocked, but merges are.
147
+
148
+ ## Notes
149
+ - Local IDE mode uses SQLite and `QUEUE_BACKEND=inline` (no Redis). Docker/production can keep Redis via `QUEUE_BACKEND=redis`.
150
+ - Schema is created with SQLAlchemy `create_all`. There is no upgrade migration until 0.0.1 is published; `norns init --force` deletes the local database.
151
+ - Use PostgreSQL in normal deployments via `DATABASE_URL`.
152
+ - Redis backs ARQ worker execution.
153
+ - PlantUML/Kroki rendering is opt-in via `PLANTUML_URL` / `KROKI_URL` (unset means no public egress).
154
+ - An empty per-stage tool allowlist grants **no** tools. Enable **norns** (create cards, edit stages/prompts, edit the state machine, inspect the git workspace), **github**, **jira**, or **polarion** on the column **Agent** dialog. Cursor stages receive those as MCP servers; OpenAI/DeepSeek stages use the same plugins as chat tools.
155
+ - **Workspace (git repo):** each board has a checkout path and/or `https://github.com/org/repo`. Stage agents inherit the board repo; a column **Agent** can override with its own path/URL. Cursor stages then run in that checkout (local agent) instead of a throwaway `/tmp` directory; GitHub tools default to that repo. If neither board nor agent is set, Norns uses the git root of the process working directory.
156
+ - Extra MCP servers: add an **MCP** connector in Settings (stdio command or HTTP URL), then enable it under Agent → Tools. Third-party Python plugins register the `norns.plugins` entry point.
157
+ - `norns mcp --plugins norns,github,jira` runs the plugin MCP server on stdin/stdout (Cursor attaches this automatically when those tools are enabled).
158
+ - `PUT /api/cards/{id}` updates title/body only; new cards always start on the first stage.
159
+ - Change `SECRET_KEY` and `ADMIN_PASSWORD` before any shared deployment. Sessions expire after 8 hours.
@@ -0,0 +1 @@
1
+ """Norns backend package."""
@@ -0,0 +1 @@
1
+ """Norns backend application package."""
@@ -0,0 +1,3 @@
1
+ from .runner import run_stage
2
+
3
+ __all__ = ["run_stage"]