Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Li+agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Keep scope local:

## Optional Webhook Notification Flow

Adapter-side foreground intake only. Semantic policy remains in Li+operations.md.
Adapter-side foreground intake only. Semantic policy remains in Li+operations.md foreground intake rules.

Use only in hosts that can run local commands from the workspace before replying.

Expand All @@ -84,9 +84,9 @@ Use only in hosts that can run local commands from the workspace before replying
1. `LI_PLUS_WEBHOOK_STATE_DIR` from `Li+config.md` (absolute path or `workspace_root`-relative path)
2. `workspace_root/github-webhook-mcp`
3. `workspace_root/../github-webhook-mcp`
- if the bundled helper exists at `workspace_root/liplus-language/scripts/check_webhook_notifications.py` and the state dir resolves, run it with `--limit 5 --consume`
- if the bundled helper exists at `workspace_root/liplus-language/scripts/check_webhook_notifications.py` and the state dir resolves, run it in inspect mode (`--limit 5`) and pass cheap foreground hints such as repo / branch when available
- else: skip silently.
3. Mention notifications only when new items exist.
4. If the local helper surfaces items, treat them as consumed immediately and delete related generated files.
3. Mention notifications only when foreground-matched items or exceptional notable items exist.
4. Do not auto-consume the local backlog from this foreground inspect path. `claim` / `read` / `done` / `cleanup` require explicit helper commands or a deeper workflow that owns the notification.
5. Do not launch a separate AI process for webhook replies from this foreground flow.
6. Do not open the full webhook payload unless deeper inspection is actually needed.
56 changes: 50 additions & 6 deletions Li+claude.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Li+claude.md — Claude Code Hook Definitions

Layer = Adapter Layer (Claude Code binding)
Semantic source = Li+agent.md trigger contract + Model Layer / Task Layer / Operations Layer.
Semantic source = Li+agent.md trigger contract + Model Layer / Task Layer / Operations Layer foreground intake rules.
This file compiles adapter rules into Claude Code hooks.

Bootstrap target: runtime=claude only.
Expand Down Expand Up @@ -58,6 +58,12 @@ fi
HELPER="$PROJECT_ROOT/liplus-language/scripts/check_webhook_notifications.py"
[ -f "$HELPER" ] || exit 0

repo_from_origin() {
git -C "$PROJECT_ROOT" remote get-url origin 2>/dev/null \
| grep -oE '[^/@:]+/[^/]+$' \
| sed 's/\.git$//' 2>/dev/null || echo ""
}

# Parse LI_PLUS_WEBHOOK_STATE_DIR from Li+config.md if set
CONFIG_MD="$PROJECT_ROOT/Li+config.md"
STATE_DIR_ARGS=()
Expand All @@ -66,17 +72,55 @@ if [ -f "$CONFIG_MD" ]; then
[ -n "$VAL" ] && STATE_DIR_ARGS=(--state-dir "$VAL")
fi

RESULT=$(python3 "$HELPER" --workspace-root "$PROJECT_ROOT" "${STATE_DIR_ARGS[@]}" --limit 5 2>/dev/null)
CURRENT_REPO=$(repo_from_origin)
CURRENT_BRANCH=$(git -C "$PROJECT_ROOT" branch --show-current 2>/dev/null || echo "")

HELPER_ARGS=(
--workspace-root "$PROJECT_ROOT"
"${STATE_DIR_ARGS[@]}"
--limit 5
--internal-sender liplus-lin-lay
--internal-sender lipluscodex
)
[ -n "$CURRENT_REPO" ] && HELPER_ARGS+=(--repo "$CURRENT_REPO")
if [ -n "$CURRENT_BRANCH" ]; then
HELPER_ARGS+=(--branch "$CURRENT_BRANCH" --infer-numbers-from-branch)
fi

RESULT=$(python3 "$HELPER" "${HELPER_ARGS[@]}" 2>/dev/null)
[ -z "$RESULT" ] && exit 0

PENDING=$(printf '%s' "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('pending_count',0))" 2>/dev/null)
if [ -z "$PENDING" ] || [ "$PENDING" = "0" ]; then
DISPLAY_LINES=$(printf '%s' "$RESULT" | python3 -c '
import json
import sys

SUCCESS = {"success", "skipped", "neutral"}
data = json.load(sys.stdin)
seen = set()
lines = []
for bucket, label in (("relevant_items", "foreground"), ("notable_items", "notable")):
for item in data.get(bucket, []):
event_id = item.get("id")
if event_id in seen:
continue
if bucket == "relevant_items":
if item.get("type") in {"check_run", "workflow_run"} and item.get("conclusion") in SUCCESS:
continue
seen.add(event_id)
number = item.get("number")
title = item.get("title") or item.get("type") or "notification"
event_type = item.get("type") or "event"
prefix = f"#{number} " if number is not None else ""
lines.append(f"[{label}] {event_type} {prefix}{title}")
print("\\n".join(lines))
' 2>/dev/null)
if [ -z "$DISPLAY_LINES" ]; then
exit 0
fi

echo ""
echo "━━━ Webhook: $PENDING pending notification(s) ━━━"
echo "Run: check_webhook_notifications.py --consume or use mcp__github-webhook-mcp"
echo "━━━ Webhook: foreground/notable notification(s) ━━━"
printf '%s\n' "$DISPLAY_LINES"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
```

Expand Down
28 changes: 10 additions & 18 deletions Li+core.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,27 +100,19 @@ Purpose: reproduce judgment across sessions and across different AIs.
Layer Definition
----------------

Four layers. Each program file declares its own layer membership.
This section defines layer roles only, not file names.
Five layers. Each program file declares its own layer membership.
Core defines layer existence and attachment order only.
Detailed role definitions belong to each layer file.

Model Layer:
invariants, intra-layer order, dialogue surface, behavioral style, task mode.
Foundation of the Li+ program. All other layers depend on this.

Task Layer:
issue rules, label vocabulary, issue-body convergence, parent/child structure.
Defines how work units are tracked and managed.

Operations Layer:
branch / commit / change request / verification / merge / release procedures.
Event-driven surface. Loaded on demand, not every session.

Adapter Layer:
host injection, runtime triggers, reread wiring, platform-specific bindings.
Connects Li+ program to the host environment.
Layers:
Model Layer
Task Layer
Operations Layer
Notifications Layer
Adapter Layer

Attachment chain:
model -> task -> operations -> adapter
model -> task -> operations -> notifications -> adapter
Attachment chain = dependency order only

Cross-layer rule:
Expand Down
9 changes: 5 additions & 4 deletions Li+operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,13 +310,14 @@ Event-Driven Operations
b = {workspace_root}/github-webhook-mcp
c = {workspace_root}/../github-webhook-mcp
if helper missing or state dir unresolved = skip silently
helper output = latest lightweight summaries only
on consume = drain all current pending events immediately and delete related generated files
helper output = inspect summary with foreground-matched items, notable items, and cleanup candidates
helper default = inspect only; preserve unmatched backlog
destructive actions = explicit `read` / `done` / `claim` / `cleanup-safe-success` calls only

foreground handling:
each user turn start = inspect once before main reply
pending_count == 0 = no mention
pending_count > 0 = brief mention before main reply
mention only = foreground-matched items or exceptional notable items
if relevance cannot be judged cheaply = preserve and stay silent
full payload = open only when deeper inspection is needed
separate AI process launch = prohibited for this flow

Expand Down
7 changes: 5 additions & 2 deletions docs/1.-Model.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ Li+ では、次の3つを別軸として扱う。

レイヤーごとに責務と再読込・再適用の条件を持つ。優先順は同一レイヤーの内部にだけ定義し、別レイヤー同士を勝敗関係として扱わない。

4層構成。各プログラムファイルが自身のレイヤーを冒頭で宣言する。
5層構成。各プログラムファイルが自身のレイヤーを冒頭で宣言する。

**Model Layer:**
不変原則、層内順序、対話面、挙動スタイル、タスクモード。Li+ program の基盤。他の全レイヤーがこれに依存する。
Expand All @@ -119,10 +119,13 @@ Li+ では、次の3つを別軸として扱う。
**Operations Layer:**
ブランチ / コミット / 変更要求 / 検証 / マージ / リリースの手順。イベント駆動。毎セッション必須ではない。

**Notifications Layer:**
GitHub Notifications API / webhook / local state fallback を横断する通知意味論。前景一致判定、claim/read/done、会話言及、janitor cleanup を定義する。

**Adapter Layer:**
ホスト注入、ランタイムトリガー、再読込配線、プラットフォーム固有バインディング。Li+ program をホスト環境へ接続する。

接続チェーン: model → task → operations → adapter(依存順序のみ)
接続チェーン: model → task → operations → notifications → adapter(依存順序のみ)

---

Expand Down
2 changes: 2 additions & 0 deletions docs/3.-Operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ DELETE /notifications/threads/{id} -> 204 完了(Inbox から除

scope = `notifications`(classic PAT)

通知 API の生操作はオペレーションレイヤーから参照してよい。ただし、前景関連性判定、`claim`、`ack/read`、`consume/done`、`mention`、`cleanup` の意味論は [5. Notifications](5.-Notifications) を正本とする。

---

## Discussions
Expand Down
6 changes: 4 additions & 2 deletions docs/4.-Adapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ hook は Claude Code ランタイムが強制発火するため、AI の記憶

動作:
1. Character Instance 再通知:`.claude/CLAUDE.md` から Character Instance セクションを抽出して出力する。見つからない場合はスキップする。
2. Webhook 通知チェック:bundled helper が存在し pending_count > 0 なら件数を出力する。それ以外は何もしない
2. 通知取り込み:利用可能な通知源を1回 `inspect` し、[5. Notifications](5.-Notifications) の規則で前景一致した summary だけをホストへ渡す。empty/no-op は出力しない

### post-tool-use.sh

Expand Down Expand Up @@ -91,12 +91,14 @@ bootstrap は次回セッションから有効。現セッションは Li+config

ホストが各ターン先頭でローカル確認を実行できる場合のみ使用する。確認処理は内部 housekeeping として無言で行い、確認中であることや empty/no-op 結果を会話へ出さない。

アダプターが所有するのは transport の選択と summary の受け渡しである。関連性判定、`claim`、`ack/read`、`consume/done`、`mention`、`cleanup` の正本は [5. Notifications](5.-Notifications) に置く。

通知源の優先順位:
1. `mcp__github-webhook-mcp`
2. ローカル webhook ストア(`LI_PLUS_MODE=clone` かつ bundled helper が使える場合)
3. 利用不可 → 黙ってスキップ

pending が0件なら何も言わない。pending がある時だけ短く通知する。詳細が必要になるまでは full payload を開かない。このフローから別 AI プロセスを起動しない。
アダプターは `inspect` を既定とし、前景一致しない通知を勝手に排水しない。詳細が必要になるまでは full payload を開かない。このフローから別 AI プロセスを起動しない。

---

Expand Down
138 changes: 138 additions & 0 deletions docs/5.-Notifications.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# 通知レイヤー仕様書

本文書は Li+ プログラムの通知レイヤーの仕様を定義する。
要求(何を満たすか)と仕様(どう振る舞うか)を一体として記述する。

通知レイヤーは、GitHub Notifications API、webhook、ローカル state dir、将来の受動受信をまたいで共通に使う意味論を定義する。polling か push かは transport の違いであり、通知の ownership と前景会話への出し方は本文書を正本とする。

---

## 目的

Li+ は前景セッションで軽量な通知差分を扱うが、共有 queue を雑に排水すると別 AI や別セッションの作業面を壊す。通知レイヤーは、通知の確認、所有、既読化、完了、会話への言及、清掃を分離し、前景スレッドの安定性を守る。

特に以下を満たす:

- 前景セッションに関係する通知だけを選択して扱える
- 関係のない通知を勝手に消費しない
- 重要な前景外通知だけを例外的に会話へ出せる
- 明らかに無害で放置された stale 通知だけを清掃できる
- 将来 transport が受動受信へ変わっても上位意味論を変えない

---

## 基本操作

通知レイヤーは次の操作を区別する。

| 操作 | 意味 |
|------|------|
| `inspect` | 未処理通知を読む。ownership は変えない |
| `claim` | 現在の前景セッションがその通知を担当対象として確保する |
| `ack/read` | 読んだことを記録する。Inbox から消すとは限らない |
| `consume/done` | 処理済みまたは意図的破棄として active queue から外す |
| `mention` | 現在の会話へ通知を出す |
| `cleanup` | 応答不要な stale 通知を janitor 的に片づける |

`claim` は `ack/read` でも `consume/done` でもない。所有権の宣言であり、会話への言及や queue からの除去とは別に扱う。

---

## 前景セッションの既定

各ユーザーターンの先頭で、前景セッションは通知源を1回だけ `inspect` してよい。確認自体は内部 housekeeping であり、確認中であることや empty/no-op 結果を会話へ出さない。

前景一致判定は可能な限り機械的に行う。優先する手掛かりは以下:

- 現在扱っている repository
- 現在の issue / PR / Discussion 番号
- 現在の linked branch
- 進行中タスクと直接結び付く workflow / check / review 対象

既定動作は次のとおり:

- 前景一致した通知だけを `claim` 対象にできる
- 前景一致した通知だけを `ack/read` または `consume/done` 候補にできる
- 関連性が安価に判定できない通知は `mention` せず、`consume/done` もしない
- 判断不能時の既定は「黙る・残す」に倒す

---

## 例外的な会話言及

前景外通知でも、重要性が高い場合に限り `mention` を許可する。これは queue ownership とは別判断であり、`mention` したからといって自動で `consume/done` しない。

例外候補:

- 外部人間からの Discussion / issue / PR コメント
- 現在の作業を止めうる failure / blocking / review request
- 自分たち以外からの明示的な呼びかけ

曖昧な通知は例外扱いしない。

---

## マルチ AI 共有キュー

Codex と Claude Code など複数の AI が同じ repository の通知 queue を共有する場合、一方の前景セッションが他方の通知を勝手に排水してはならない。

そのため、transport が許すなら通知 state は次を持てる形が望ましい:

- `claimed_by`
- `claimed_at`
- `consumed_at`
- `reason`

transport 自体に `claim` が無い場合は sidecar metadata で補う。どちらも使えない場合、破壊的な `consume/done` より preserve を優先する。

`drain all pending events` は暫定 helper 実装として存在しても、上位意味論の正本にはしない。

---

## 清掃(Janitor)

前景一致しない通知でも、明らかに誰の応答も不要で、かつ一定時間以上放置された無害通知だけは `cleanup` してよい。

清掃候補:

- 自分たちが発行した `check_run` / `workflow_run` の success
- 重複している自動生成通知
- 後続イベントで意味を失った generated artifact

清掃禁止:

- 人間の comment / Discussion / review
- failure / blocking / changes requested
- ownership が曖昧な通知
- relevance を安価に判定できない通知

清掃は relevance 判断の代替ではない。安全に無視できるものだけを対象にする。

---

## Transport Binding

理想の意味論は GitHub Notifications API に寄せる。

| 意味論 | GitHub Notifications API | Webhook / local state fallback |
|--------|--------------------------|--------------------------------|
| `inspect` | `GET /notifications?all=false` | pending event の一覧取得 |
| `ack/read` | `PATCH /notifications/threads/{id}` | read 相当の state 更新 |
| `consume/done` | `DELETE /notifications/threads/{id}` | pending queue から除去 |
| `claim` | API 非対応。sidecar で補う | sidecar または state file で補う |

transport は polling でも push でもよい。前景一致判定、例外的 `mention`、janitor `cleanup` の規則は transport によって変えない。

---

## 他レイヤーとの接続

**Operations Layer:** CI / review / release 待機で必要なイベント種別を定義するが、共有 queue の ownership と cleanup 規則は通知レイヤーを再定義しない。

**Adapter Layer:** 各ターン先頭で transport を `inspect` し、前景へ渡す summary を整える。関連性判断と destructive consume の正本は通知レイヤーに従う。

---

## 進化

再構築・削除・最適化はすべて許容する。構造の一貫性のみ維持する。
1 change: 1 addition & 0 deletions docs/Home.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Li+ v1.0.0 の成立条件は到達済みとみなし、現在の本番はその
| [2. Task](2.-Task) | タスクレイヤー仕様書 |
| [3. Operations](3.-Operations) | オペレーションレイヤー仕様書 |
| [4. Adapter](4.-Adapter) | アダプターレイヤー仕様書 |
| [5. Notifications](5.-Notifications) | 通知レイヤー仕様書 |

---

Expand Down
Loading
Loading