@onlooker-community/ecosystem 0.29.3 → 0.30.1
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.
- package/.claude-plugin/plugin.json +1 -1
- package/.release-please-manifest.json +6 -6
- package/CHANGELOG.md +19 -0
- package/CLAUDE.md +10 -0
- package/package.json +1 -1
- package/plugins/archivist/.claude-plugin/plugin.json +1 -1
- package/plugins/archivist/CHANGELOG.md +7 -0
- package/plugins/archivist/scripts/hooks/archivist-extract.sh +34 -0
- package/plugins/archivist/scripts/lib/archivist-events.sh +80 -0
- package/plugins/counsel/.claude-plugin/plugin.json +1 -1
- package/plugins/counsel/CHANGELOG.md +7 -0
- package/plugins/counsel/scripts/lib/counsel-brief.sh +23 -0
- package/plugins/historian/.claude-plugin/plugin.json +1 -1
- package/plugins/historian/CHANGELOG.md +7 -0
- package/plugins/historian/scripts/hooks/historian-session-end.sh +2 -4
- package/plugins/historian/scripts/lib/historian-embedder.sh +10 -6
- package/plugins/librarian/.claude-plugin/plugin.json +1 -1
- package/plugins/librarian/CHANGELOG.md +7 -0
- package/plugins/librarian/scripts/hooks/librarian-session-end.sh +37 -0
- package/plugins/scribe/.claude-plugin/plugin.json +1 -1
- package/plugins/scribe/CHANGELOG.md +7 -0
- package/plugins/scribe/scripts/lib/scribe-distill.sh +16 -0
- package/test/bats/historian-prompt-submit.bats +1 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ecosystem",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.1",
|
|
4
4
|
"description": "Observability substrate for Claude Code. Provides the shared $ONLOOKER_DIR storage root (default $HOME/.onlooker), canonical schema-validated event emission, session and tool tracking hooks, and prompt rules. Required by all other Onlooker plugins.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Onlooker Community",
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
|
-
".": "0.
|
|
3
|
-
"plugins/archivist": "0.
|
|
2
|
+
".": "0.30.1",
|
|
3
|
+
"plugins/archivist": "0.2.0",
|
|
4
4
|
"plugins/tribunal": "1.0.1",
|
|
5
5
|
"plugins/echo": "0.2.0",
|
|
6
6
|
"plugins/cartographer": "0.2.1",
|
|
7
7
|
"plugins/governor": "0.2.1",
|
|
8
8
|
"plugins/compass": "0.3.0",
|
|
9
|
-
"plugins/scribe": "0.
|
|
10
|
-
"plugins/counsel": "0.
|
|
9
|
+
"plugins/scribe": "0.3.0",
|
|
10
|
+
"plugins/counsel": "0.4.0",
|
|
11
11
|
"plugins/warden": "0.2.0",
|
|
12
|
-
"plugins/librarian": "0.
|
|
12
|
+
"plugins/librarian": "0.3.0",
|
|
13
13
|
"plugins/curator": "0.1.0",
|
|
14
|
-
"plugins/historian": "0.2.
|
|
14
|
+
"plugins/historian": "0.2.1",
|
|
15
15
|
"plugins/assayer": "1.0.0",
|
|
16
16
|
"plugins/bursar": "0.1.1",
|
|
17
17
|
"plugins/lineage": "0.1.0",
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.30.1](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.30.0...ecosystem-v0.30.1) (2026-06-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **historian:** repair CI broken by embedder check + document PR workflow :nail_care: ([#106](https://github.com/onlooker-community/ecosystem/issues/106)) ([02062a2](https://github.com/onlooker-community/ecosystem/commit/02062a21163e084705dae9cf421719b6e5a7b306))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Performance Improvements
|
|
12
|
+
|
|
13
|
+
* **historian:** fix O(n²) chunk loop and embedder false-positive :relieved: ([4ef130a](https://github.com/onlooker-community/ecosystem/commit/4ef130a4c01ec378da5b4d8baeeb7b4fb6059272))
|
|
14
|
+
|
|
15
|
+
## [0.30.0](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.29.3...ecosystem-v0.30.0) (2026-06-24)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* **plugins:** persist structured JSON and emit onlooker.artifact.ready :outbox_tray: ([#103](https://github.com/onlooker-community/ecosystem/issues/103)) ([9b689a4](https://github.com/onlooker-community/ecosystem/commit/9b689a41aa4bdb481fef93b484e6446da731e8f1))
|
|
21
|
+
|
|
3
22
|
## [0.29.3](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.29.2...ecosystem-v0.29.3) (2026-06-24)
|
|
4
23
|
|
|
5
24
|
|
package/CLAUDE.md
CHANGED
|
@@ -87,6 +87,16 @@ npm run test:ci # shellcheck + bats + schema + lint
|
|
|
87
87
|
|
|
88
88
|
Tests use an isolated temp home; nothing writes to your real `~/.onlooker/`.
|
|
89
89
|
|
|
90
|
+
## Git workflow
|
|
91
|
+
|
|
92
|
+
**Always open a PR — never push directly to `main`.** Even though bypass rights allow direct pushes, this repo uses release-please for automated changelogs and versioning, so every change must travel through a PR to be picked up correctly. CI also runs on PRs before merge, catching failures before they land.
|
|
93
|
+
|
|
94
|
+
Workflow:
|
|
95
|
+
1. Create a feature branch: `git switch -c <type>/<short-description>`
|
|
96
|
+
2. Commit using `/commit`
|
|
97
|
+
3. Push the branch and open a PR using `/git:gh-pr-create`
|
|
98
|
+
4. Wait for CI to pass before merging
|
|
99
|
+
|
|
90
100
|
## Conventions
|
|
91
101
|
|
|
92
102
|
- All hooks are bash scripts. No Python, no Node entry points in hook scripts (they may shell out to `node` for event emission or heavy lifting).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "archivist",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Structured session memory across context truncation: extracts decisions, dead ends, and open questions on PreCompact and reinjects the most important items at SessionStart. Builds on the Onlooker ecosystem plugin.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Onlooker Community",
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.0](https://github.com/onlooker-community/ecosystem/compare/archivist-v0.1.0...archivist-v0.2.0) (2026-06-24)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **plugins:** persist structured JSON and emit onlooker.artifact.ready :outbox_tray: ([#103](https://github.com/onlooker-community/ecosystem/issues/103)) ([9b689a4](https://github.com/onlooker-community/ecosystem/commit/9b689a41aa4bdb481fef93b484e6446da731e8f1))
|
|
9
|
+
|
|
3
10
|
## [0.1.0](https://github.com/onlooker-community/ecosystem/compare/archivist-v0.0.1...archivist-v0.1.0) (2026-05-23)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -44,6 +44,8 @@ source "${PLUGIN_ROOT}/scripts/lib/archivist-ulid.sh"
|
|
|
44
44
|
source "${PLUGIN_ROOT}/scripts/lib/archivist-storage.sh"
|
|
45
45
|
# shellcheck source=../lib/archivist-config.sh
|
|
46
46
|
source "${PLUGIN_ROOT}/scripts/lib/archivist-config.sh"
|
|
47
|
+
# shellcheck source=../lib/archivist-events.sh
|
|
48
|
+
CLAUDE_PLUGIN_ROOT="${_ECOSYSTEM_ROOT:-$PLUGIN_ROOT}" source "${PLUGIN_ROOT}/scripts/lib/archivist-events.sh"
|
|
47
49
|
|
|
48
50
|
# Always approve compaction at exit, no matter what happened above.
|
|
49
51
|
_approve() {
|
|
@@ -234,5 +236,37 @@ for KIND_PAIR in "decisions:decision" "dead_ends:dead_end" "open_questions:open_
|
|
|
234
236
|
done
|
|
235
237
|
done
|
|
236
238
|
|
|
239
|
+
# Write an aggregate extract JSON for the artifact browser. This is the
|
|
240
|
+
# single-file representation of everything extracted this compact cycle:
|
|
241
|
+
# decisions, dead ends, and open questions in one document. The session_id
|
|
242
|
+
# doubles as the artifact key so the stable uuid from artifact.FromEvent
|
|
243
|
+
# deduplicates re-uploads of the same session.
|
|
244
|
+
if [[ "$WRITE_COUNT" -gt 0 && -n "$SESSION_ID" ]]; then
|
|
245
|
+
EXTRACTS_DIR="$(archivist_project_dir "$PROJECT_KEY")/extracts"
|
|
246
|
+
mkdir -p "$EXTRACTS_DIR" 2>/dev/null || true
|
|
247
|
+
EXTRACT_PATH="${EXTRACTS_DIR}/${SESSION_ID}.json"
|
|
248
|
+
|
|
249
|
+
AGGREGATE=$(jq -n \
|
|
250
|
+
--argjson decisions "$(printf '%s' "$CLEAN_RESPONSE" | jq '.decisions // []')" \
|
|
251
|
+
--argjson dead_ends "$(printf '%s' "$CLEAN_RESPONSE" | jq '.dead_ends // []')" \
|
|
252
|
+
--argjson open_questions "$(printf '%s' "$CLEAN_RESPONSE" | jq '.open_questions // []')" \
|
|
253
|
+
'{decisions: $decisions, dead_ends: $dead_ends, open_questions: $open_questions}') || AGGREGATE=""
|
|
254
|
+
|
|
255
|
+
if [[ -n "$AGGREGATE" ]]; then
|
|
256
|
+
printf '%s\n' "$AGGREGATE" > "$EXTRACT_PATH" 2>/dev/null || true
|
|
257
|
+
|
|
258
|
+
SESSION_SHORT="${SESSION_ID:0:8}"
|
|
259
|
+
ARTIFACT_PAYLOAD=$(jq -n \
|
|
260
|
+
--arg plugin "archivist" \
|
|
261
|
+
--arg artifact_kind "extract" \
|
|
262
|
+
--arg artifact_path "$EXTRACT_PATH" \
|
|
263
|
+
--arg artifact_title "Archivist Extract · $SESSION_SHORT" \
|
|
264
|
+
'{plugin: $plugin, artifact_kind: $artifact_kind,
|
|
265
|
+
artifact_path: $artifact_path, artifact_title: $artifact_title}') || ARTIFACT_PAYLOAD=""
|
|
266
|
+
[[ -n "$ARTIFACT_PAYLOAD" ]] && \
|
|
267
|
+
archivist_emit_event "onlooker.artifact.ready" "$ARTIFACT_PAYLOAD" || true
|
|
268
|
+
fi
|
|
269
|
+
fi
|
|
270
|
+
|
|
237
271
|
_approve "Archivist: wrote ${WRITE_COUNT} artifacts (trigger=${TRIGGER})"
|
|
238
272
|
exit 0
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Canonical archivist.* event emission.
|
|
3
|
+
#
|
|
4
|
+
# Thin wrapper around the ecosystem plugin's onlooker-event.mjs `emit` mode.
|
|
5
|
+
# Every emission is validated against @onlooker-community/schema before being
|
|
6
|
+
# appended to $ONLOOKER_EVENTS_LOG (defaults to $ONLOOKER_DIR/logs/onlooker-events.jsonl).
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# archivist_emit_event "onlooker.artifact.ready" \
|
|
10
|
+
# '{"plugin":"archivist","artifact_kind":"extract","artifact_path":"...","artifact_title":"..."}'
|
|
11
|
+
|
|
12
|
+
_ARCHIVIST_PLUGIN_NAME="archivist"
|
|
13
|
+
|
|
14
|
+
_archivist_event_js_path() {
|
|
15
|
+
if [[ -n "${_ONLOOKER_EVENT_JS:-}" && -f "$_ONLOOKER_EVENT_JS" ]]; then
|
|
16
|
+
printf '%s' "$_ONLOOKER_EVENT_JS"
|
|
17
|
+
return 0
|
|
18
|
+
fi
|
|
19
|
+
local plugin_root="${CLAUDE_PLUGIN_ROOT:-}"
|
|
20
|
+
local candidates=(
|
|
21
|
+
"${plugin_root}/scripts/lib/onlooker-event.mjs"
|
|
22
|
+
"${plugin_root}/../../scripts/lib/onlooker-event.mjs"
|
|
23
|
+
)
|
|
24
|
+
local c
|
|
25
|
+
for c in "${candidates[@]}"; do
|
|
26
|
+
[[ -f "$c" ]] && { printf '%s' "$c"; return 0; }
|
|
27
|
+
done
|
|
28
|
+
return 1
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
_archivist_session_id() {
|
|
32
|
+
if [[ -n "${_HOOK_SESSION_ID:-}" ]]; then
|
|
33
|
+
printf '%s' "$_HOOK_SESSION_ID"
|
|
34
|
+
return 0
|
|
35
|
+
fi
|
|
36
|
+
if [[ -n "${CLAUDE_SESSION_ID:-}" ]]; then
|
|
37
|
+
printf '%s' "$CLAUDE_SESSION_ID"
|
|
38
|
+
return 0
|
|
39
|
+
fi
|
|
40
|
+
printf 'unknown'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
archivist_emit_event() {
|
|
44
|
+
local event_type="${1:-}"
|
|
45
|
+
local payload="${2:-}"
|
|
46
|
+
|
|
47
|
+
[[ -z "$event_type" || -z "$payload" ]] && return 1
|
|
48
|
+
|
|
49
|
+
local event_js
|
|
50
|
+
event_js=$(_archivist_event_js_path) || return 1
|
|
51
|
+
|
|
52
|
+
local session_id
|
|
53
|
+
session_id=$(_archivist_session_id)
|
|
54
|
+
|
|
55
|
+
local params
|
|
56
|
+
params=$(jq -n \
|
|
57
|
+
--arg plugin "$_ARCHIVIST_PLUGIN_NAME" \
|
|
58
|
+
--arg sid "$session_id" \
|
|
59
|
+
--arg type "$event_type" \
|
|
60
|
+
--argjson payload "$payload" \
|
|
61
|
+
'{plugin: $plugin, session_id: $sid, event_type: $type, payload: $payload}' \
|
|
62
|
+
2>/dev/null) || return 1
|
|
63
|
+
|
|
64
|
+
local event stderr_file
|
|
65
|
+
stderr_file=$(mktemp -t archivist-event-err.XXXXXX 2>/dev/null) || stderr_file="/tmp/archivist-event-err.$$"
|
|
66
|
+
event=$(printf '%s' "$params" \
|
|
67
|
+
| ONLOOKER_DIR="${ONLOOKER_DIR:-$HOME/.onlooker}" \
|
|
68
|
+
ONLOOKER_PLUGIN_NAME="$_ARCHIVIST_PLUGIN_NAME" \
|
|
69
|
+
node "$event_js" emit 2>"$stderr_file") || {
|
|
70
|
+
printf 'archivist_emit_event: schema validation failed for %s\n' "$event_type" >&2
|
|
71
|
+
[[ -s "$stderr_file" ]] && cat "$stderr_file" >&2
|
|
72
|
+
rm -f "$stderr_file"
|
|
73
|
+
return 1
|
|
74
|
+
}
|
|
75
|
+
rm -f "$stderr_file"
|
|
76
|
+
|
|
77
|
+
local log_path="${ONLOOKER_EVENTS_LOG:-${ONLOOKER_DIR:-$HOME/.onlooker}/logs/onlooker-events.jsonl}"
|
|
78
|
+
mkdir -p "$(dirname "$log_path")" 2>/dev/null || return 1
|
|
79
|
+
printf '%s\n' "$event" >> "$log_path"
|
|
80
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "counsel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Weekly synthesis and recommendations from the full observability stack. Reads all plugin event logs, produces a structured improvement brief, and injects it at session start when the last brief is stale.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Onlooker Community",
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.0](https://github.com/onlooker-community/ecosystem/compare/counsel-v0.3.1...counsel-v0.4.0) (2026-06-24)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **plugins:** persist structured JSON and emit onlooker.artifact.ready :outbox_tray: ([#103](https://github.com/onlooker-community/ecosystem/issues/103)) ([9b689a4](https://github.com/onlooker-community/ecosystem/commit/9b689a41aa4bdb481fef93b484e6446da731e8f1))
|
|
9
|
+
|
|
3
10
|
## [0.3.1](https://github.com/onlooker-community/ecosystem/compare/counsel-v0.3.0...counsel-v0.3.1) (2026-06-12)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -248,6 +248,18 @@ counsel_generate_brief() {
|
|
|
248
248
|
return 1
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
+
# Also persist structured JSON alongside the markdown so the agent can
|
|
252
|
+
# upload full brief content without re-parsing markdown.
|
|
253
|
+
local json_path="${briefs_dir}/${week_label}.json"
|
|
254
|
+
local full_brief_json
|
|
255
|
+
full_brief_json=$(printf '%s' "$brief_json" | jq \
|
|
256
|
+
--arg ps "$period_start" \
|
|
257
|
+
--arg pe "$period_end" \
|
|
258
|
+
--argjson src "$sources_json" \
|
|
259
|
+
'. + {period_start: $ps, period_end: $pe, sources_consulted: $src}' 2>/dev/null) \
|
|
260
|
+
|| full_brief_json="$brief_json"
|
|
261
|
+
printf '%s\n' "$full_brief_json" > "$json_path" 2>/dev/null || true
|
|
262
|
+
|
|
251
263
|
# Emit counsel.brief.generated.
|
|
252
264
|
local rec_count
|
|
253
265
|
rec_count=$(printf '%s' "$brief_json" | jq '.recommendations | length' 2>/dev/null) || rec_count=0
|
|
@@ -268,5 +280,16 @@ counsel_generate_brief() {
|
|
|
268
280
|
printf 'counsel_generate_brief: skipped counsel.brief.generated (no valid period bounds)\n' >&2
|
|
269
281
|
fi
|
|
270
282
|
|
|
283
|
+
# Emit onlooker.artifact.ready so the agent can upload the full brief content.
|
|
284
|
+
local artifact_payload
|
|
285
|
+
artifact_payload=$(jq -n \
|
|
286
|
+
--arg plugin "counsel" \
|
|
287
|
+
--arg artifact_kind "brief" \
|
|
288
|
+
--arg artifact_path "$json_path" \
|
|
289
|
+
--arg artifact_title "Counsel Brief · $week_label" \
|
|
290
|
+
'{plugin: $plugin, artifact_kind: $artifact_kind,
|
|
291
|
+
artifact_path: $artifact_path, artifact_title: $artifact_title}') || artifact_payload=""
|
|
292
|
+
[[ -n "$artifact_payload" ]] && counsel_emit_event "onlooker.artifact.ready" "$artifact_payload" || true
|
|
293
|
+
|
|
271
294
|
printf '%s' "$output_path"
|
|
272
295
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "historian",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Episodic memory layer. At SessionEnd, chunks and sanitizes the session transcript and stores chunks under $ONLOOKER_DIR/historian/<project-key>/sessions/ (default $HOME/.onlooker). On UserPromptSubmit, embeds the prompt and performs similarity retrieval over stored chunks to surface relevant past context. Builds on the Onlooker ecosystem plugin.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Onlooker Community",
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.1](https://github.com/onlooker-community/ecosystem/compare/historian-v0.2.0...historian-v0.2.1) (2026-06-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Performance Improvements
|
|
7
|
+
|
|
8
|
+
* **historian:** fix O(n²) chunk loop and embedder false-positive :relieved: ([4ef130a](https://github.com/onlooker-community/ecosystem/commit/4ef130a4c01ec378da5b4d8baeeb7b4fb6059272))
|
|
9
|
+
|
|
3
10
|
## [0.2.0](https://github.com/onlooker-community/ecosystem/compare/historian-v0.1.0...historian-v0.2.0) (2026-06-04)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -162,10 +162,8 @@ historian_storage_reset_session "$PROJECT_KEY" "$SESSION_ID"
|
|
|
162
162
|
|
|
163
163
|
NOW_TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
164
164
|
CHUNKS_INDEXED=0
|
|
165
|
-
KEPT_COUNT=$(printf '%s' "$KEPT" | jq 'length' 2>/dev/null) || KEPT_COUNT=0
|
|
166
165
|
|
|
167
|
-
|
|
168
|
-
CHUNK=$(printf '%s' "$KEPT" | jq -c ".[$i]")
|
|
166
|
+
while IFS= read -r CHUNK; do
|
|
169
167
|
[[ -z "$CHUNK" || "$CHUNK" == "null" ]] && continue
|
|
170
168
|
|
|
171
169
|
CHUNK_ID=$(historian_ulid)
|
|
@@ -203,7 +201,7 @@ for ((i = 0; i < KEPT_COUNT; i++)); do
|
|
|
203
201
|
'{ chunk_id: $chunk_id, redaction_count: $redaction_count }')"
|
|
204
202
|
fi
|
|
205
203
|
fi
|
|
206
|
-
done
|
|
204
|
+
done < <(printf '%s' "$KEPT" | jq -c '.[]' 2>/dev/null)
|
|
207
205
|
|
|
208
206
|
# Emit one chunk.dropped event per skip reason summary (caps at the
|
|
209
207
|
# number of unique reasons; per-chunk emission would spam the log).
|
|
@@ -43,8 +43,8 @@ _historian_embedder_ollama_timeout() {
|
|
|
43
43
|
printf '%s' "$v"
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
# Returns 0 if the currently-configured embedder is reachable
|
|
47
|
-
#
|
|
46
|
+
# Returns 0 if the currently-configured embedder is reachable AND the
|
|
47
|
+
# target model is installed. A side-effect-free probe.
|
|
48
48
|
historian_embedder_available() {
|
|
49
49
|
local backend
|
|
50
50
|
backend=$(_historian_embedder_backend)
|
|
@@ -54,12 +54,16 @@ historian_embedder_available() {
|
|
|
54
54
|
;;
|
|
55
55
|
ollama)
|
|
56
56
|
command -v curl >/dev/null 2>&1 || return 1
|
|
57
|
-
local host timeout
|
|
57
|
+
local host model timeout tags
|
|
58
58
|
host=$(_historian_embedder_ollama_host)
|
|
59
|
+
model=$(_historian_embedder_ollama_model)
|
|
59
60
|
timeout=$(_historian_embedder_ollama_timeout)
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
curl -fsS --max-time "$timeout"
|
|
61
|
+
# Fetch the model list and verify the configured model is present.
|
|
62
|
+
# An empty models list (ollama running but no models pulled) returns 1.
|
|
63
|
+
tags=$(curl -fsS --max-time "$timeout" "${host}/api/tags" 2>/dev/null) || return 1
|
|
64
|
+
printf '%s' "$tags" | jq -e --arg m "$model" \
|
|
65
|
+
'.models[]? | select(.name == $m or (.name | startswith($m + ":")))' \
|
|
66
|
+
>/dev/null 2>&1
|
|
63
67
|
;;
|
|
64
68
|
*)
|
|
65
69
|
# fastembed / remote backends not implemented yet — treat as
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "librarian",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Consolidation layer between archivist's per-session artifacts and the user's durable typed memory store. Detects which session decisions, dead-ends, and open questions deserve to live across sessions, classifies them into the user/feedback/project/reference types, and queues them as proposals for explicit confirmation. Auto-promotion is opt-in. Builds on the Onlooker ecosystem plugin.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Onlooker Community",
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.0](https://github.com/onlooker-community/ecosystem/compare/librarian-v0.2.0...librarian-v0.3.0) (2026-06-24)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **plugins:** persist structured JSON and emit onlooker.artifact.ready :outbox_tray: ([#103](https://github.com/onlooker-community/ecosystem/issues/103)) ([9b689a4](https://github.com/onlooker-community/ecosystem/commit/9b689a41aa4bdb481fef93b484e6446da731e8f1))
|
|
9
|
+
|
|
3
10
|
## [0.2.0](https://github.com/onlooker-community/ecosystem/compare/librarian-v0.1.0...librarian-v0.2.0) (2026-06-04)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -265,6 +265,43 @@ for ((i = 0; i < KEPT_COUNT; i++)); do
|
|
|
265
265
|
|
|
266
266
|
PROPOSED_COUNT=$((PROPOSED_COUNT + 1))
|
|
267
267
|
|
|
268
|
+
# Write a flat artifact JSON for the artifact browser. The proposal file
|
|
269
|
+
# uses a nested `proposed.*` structure; this flat copy matches the web's
|
|
270
|
+
# LibrarianContent type so the dashboard can render it directly.
|
|
271
|
+
ARTIFACT_CONTENT=$(jq -n \
|
|
272
|
+
--arg type "$MEMORY_TYPE" \
|
|
273
|
+
--arg title "$TITLE" \
|
|
274
|
+
--arg body "$BODY" \
|
|
275
|
+
--argjson classifier_confidence "$CONFIDENCE" \
|
|
276
|
+
--arg conflict_state "none" \
|
|
277
|
+
--argjson source_session_ids \
|
|
278
|
+
"$(if [[ -n "$ARTIFACT_SESSION" ]]; then
|
|
279
|
+
printf '["%s"]' "$ARTIFACT_SESSION"
|
|
280
|
+
else
|
|
281
|
+
printf '[]'
|
|
282
|
+
fi)" \
|
|
283
|
+
'{type: $type, title: $title, body: $body,
|
|
284
|
+
classifier_confidence: $classifier_confidence,
|
|
285
|
+
conflict_state: $conflict_state,
|
|
286
|
+
source_session_ids: $source_session_ids}') || ARTIFACT_CONTENT=""
|
|
287
|
+
|
|
288
|
+
if [[ -n "$ARTIFACT_CONTENT" ]]; then
|
|
289
|
+
ARTIFACTS_DIR="$(librarian_project_dir "$PROJECT_KEY")/artifacts"
|
|
290
|
+
mkdir -p "$ARTIFACTS_DIR" 2>/dev/null || true
|
|
291
|
+
ARTIFACT_PATH="${ARTIFACTS_DIR}/${PROPOSAL_ID}.json"
|
|
292
|
+
printf '%s\n' "$ARTIFACT_CONTENT" > "$ARTIFACT_PATH" 2>/dev/null || ARTIFACT_PATH=""
|
|
293
|
+
fi
|
|
294
|
+
|
|
295
|
+
if [[ -n "${ARTIFACT_PATH:-}" ]]; then
|
|
296
|
+
librarian_emit "onlooker.artifact.ready" "$SESSION_ID" "$(jq -cn \
|
|
297
|
+
--arg plugin "librarian" \
|
|
298
|
+
--arg artifact_kind "proposal" \
|
|
299
|
+
--arg artifact_path "$ARTIFACT_PATH" \
|
|
300
|
+
--arg artifact_title "$TITLE" \
|
|
301
|
+
'{plugin: $plugin, artifact_kind: $artifact_kind,
|
|
302
|
+
artifact_path: $artifact_path, artifact_title: $artifact_title}')"
|
|
303
|
+
fi
|
|
304
|
+
|
|
268
305
|
librarian_emit "librarian.candidate.proposed" "$SESSION_ID" "$(jq -cn \
|
|
269
306
|
--arg proposal_id "$PROPOSAL_ID" \
|
|
270
307
|
--arg memory_type "$MEMORY_TYPE" \
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scribe",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Intent documentation from agent activity. Captures why changes were made — problem context, decisions, tradeoffs — and distills them into readable artifacts at session end.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Onlooker Community",
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.0](https://github.com/onlooker-community/ecosystem/compare/scribe-v0.2.1...scribe-v0.3.0) (2026-06-24)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **plugins:** persist structured JSON and emit onlooker.artifact.ready :outbox_tray: ([#103](https://github.com/onlooker-community/ecosystem/issues/103)) ([9b689a4](https://github.com/onlooker-community/ecosystem/commit/9b689a41aa4bdb481fef93b484e6446da731e8f1))
|
|
9
|
+
|
|
3
10
|
## [0.2.1](https://github.com/onlooker-community/ecosystem/compare/scribe-v0.2.0...scribe-v0.2.1) (2026-06-04)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -225,6 +225,11 @@ scribe_distill() {
|
|
|
225
225
|
fi
|
|
226
226
|
fi
|
|
227
227
|
|
|
228
|
+
# Also persist the structured JSON alongside the markdown so the agent
|
|
229
|
+
# can upload it without re-parsing markdown.
|
|
230
|
+
local json_path="${output_dir}/${date_str}-${session_short}.json"
|
|
231
|
+
printf '%s\n' "$intent_json" > "$json_path" 2>/dev/null || true
|
|
232
|
+
|
|
228
233
|
# Emit scribe.distill.complete.
|
|
229
234
|
local payload
|
|
230
235
|
payload=$(jq -n \
|
|
@@ -235,5 +240,16 @@ scribe_distill() {
|
|
|
235
240
|
|
|
236
241
|
[[ -n "$payload" ]] && scribe_emit_event "scribe.distill.complete" "$payload" || true
|
|
237
242
|
|
|
243
|
+
# Emit onlooker.artifact.ready so the agent can upload the structured content.
|
|
244
|
+
local artifact_payload
|
|
245
|
+
artifact_payload=$(jq -n \
|
|
246
|
+
--arg plugin "scribe" \
|
|
247
|
+
--arg artifact_kind "intent" \
|
|
248
|
+
--arg artifact_path "$json_path" \
|
|
249
|
+
--arg artifact_title "Session Intent · $date_str" \
|
|
250
|
+
'{plugin: $plugin, artifact_kind: $artifact_kind,
|
|
251
|
+
artifact_path: $artifact_path, artifact_title: $artifact_title}') || artifact_payload=""
|
|
252
|
+
[[ -n "$artifact_payload" ]] && scribe_emit_event "onlooker.artifact.ready" "$artifact_payload" || true
|
|
253
|
+
|
|
238
254
|
printf '%s' "$output_path"
|
|
239
255
|
}
|