chore: scaffold monorepo with spec/ Lean project and governance docs

- spec/: freshly initialized Lean library project (lake init, v4.31.0), no deps
- .gitea/workflows/spec-check.yml: CI running lake build on spec/ (well-formedness gate, not a spec-to-impl gate)
- README.md: monorepo overview + the 5 "constitution" rules positioning spec/ as upstream semantic master
- CLAUDE.md: global agent manual
- spec/README.md: contract writing conventions (prose+type, PINNED/OPEN/ADR tags, no sorry)
- docs/adr/0001-0004: system-level decision records (retrieved from main)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-21 22:00:18 +08:00
commit 3a22669f0a
15 changed files with 303 additions and 0 deletions
@@ -0,0 +1,29 @@
# ADR 0001: Feishu Project Group Is The Collaboration Space
## Status
Accepted.
## Context
Teachers need to work on multiple curriculum projects at the same time. The previous mental model tied a teacher to one active project session, which makes multi-open workflows awkward and turns "exit project" into a confusing concept.
The revised product model is:
- one project has one long-lived Feishu project group;
- teachers discuss freely in the group;
- Claude does not process every group message;
- a teacher explicitly `@Claude` when Claude should join the current context and do work.
## Decision
Treat the project group as a long-lived collaboration space, not as a lock owner and not as a temporary processing session.
The group can stay open while no Claude processing is active. A teacher leaving or muting a group is separate from project permissions and from Claude processing lifecycle.
## Consequences
- Multi-open is natural: a teacher participates in multiple project groups.
- Normal group discussion does not occupy the project.
- "Exit project" should not be the normal action in the group workflow.
- Project rebinding or group archival needs explicit product rules, separate from run cancellation.
@@ -0,0 +1,30 @@
# ADR 0002: Project Lock Is Owned By AgentRun
## Status
Accepted.
## Context
The older model effectively made a long-lived teacher/project session hold the project lock. That breaks down once project groups become long-lived collaboration spaces and Claude is invoked on demand.
We need to prevent concurrent Claude executions from modifying the same project, while still allowing teachers to keep discussing the project in the group.
## Decision
Use a project-scoped lock whose owner is the current `AgentRun`.
```text
scope = project_id
owner = run_id
lifetime = one Claude processing task
```
The lock is acquired after `@Claude` creates an `AgentRun`, and released when the run completes, fails, times out or is canceled.
## Consequences
- Group membership, teacher identity and Claude provider session do not directly own the lock.
- The same long-lived `AgentSession` can be reused by many runs.
- `cancel current processing` releases the lock by `run_id`.
- Admin `force release` remains an exceptional operation for stuck runs or lost processes.
+29
View File
@@ -0,0 +1,29 @@
# ADR 0003: Read Feishu Context On Demand
## Status
Proposed.
## Context
The system needs to give Claude enough context when a teacher invokes it from a project group. Storing full Feishu group history in the Hub adds retention and privacy concerns, while fixed time windows such as "recent 24 hours" are brittle.
Feishu provides message history APIs, so the Hub can keep stable anchors and read nearby context when needed.
## Decision
For the first architecture, the Hub stores minimal anchors and project memory instead of full Feishu message history:
- chat id and project binding;
- trigger message id;
- run id and status card id;
- reply/thread anchors;
- project memory, decisions and artifact references.
Claude gets seed context from the current trigger message, project memory and recent anchors. If more context is needed, Claude calls MCP tools to read current message, reply chain, thread history or recent group messages through Feishu APIs.
## Consequences
- The Hub avoids becoming a full chat history store.
- Search over old vague discussions is limited until we add summary or indexing.
- MCP tools must authorize by run/project context; Claude cannot pass arbitrary chat ids.
@@ -0,0 +1,54 @@
# ADR 0004: Use Feishu Docs-like Permission Grants
## Status
Proposed.
## Context
Project collaboration needs more nuance than a hard-coded `owner / teacher / admin` model. Teachers may need to view a project, discuss it, trigger Claude, edit artifacts, manage members, or handle exceptional cancellation. These are related but not identical privileges.
Feishu cloud docs separates collaborators from operation settings:
- collaborators can be users, groups, departments, user groups, apps, or wiki members;
- collaborator roles are read, edit, or manage;
- settings separately control sharing outside the organization, copying/downloading, commenting, and collaborator management.
That split maps well to Curriculum Project Hub.
## Decision
Model project permissions as:
```text
PermissionGrant
- resource_type: project | artifact | project_group
- resource_id
- principal_type: user | feishu_chat | department | user_group | app
- principal_id
- role: read | edit | manage
PermissionSettings
- resource_type
- resource_id
- external_share_policy
- comment_policy
- copy_download_policy
- collaborator_management_policy
- agent_trigger_policy
- agent_cancel_policy
```
Use role-derived capabilities for ordinary actions, and settings for policy knobs:
- `read`: view project, artifacts, run history and project group metadata.
- `edit`: read plus discuss, comment, edit artifacts, trigger Claude runs and answer Claude choice cards.
- `manage`: edit plus manage collaborators, project settings, group binding and normal run cancellation policy.
- admin-only override: force release stuck locks and perform exceptional audit operations.
## Consequences
- We can grant access to a teacher, a whole Feishu project group, a department, or a custom user group using the same model.
- Claude invocation is explicit policy, not just "anyone in the group can run it" forever.
- "Who can cancel current processing" can be different from "who can force release a stuck lock".
- The model stays close to Feishu users' expectations without copying every Feishu-specific API detail.