instar 1.2.62 → 1.2.64

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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  <h1 align="center">instar</h1>
6
6
 
7
7
  <p align="center">
8
- <strong>Persistent, trustworthy Claude Code agents. Built on coherence-first architecture.</strong>
8
+ <strong>Coherence infrastructure for your self-evolving agent.</strong>
9
9
  </p>
10
10
 
11
11
  <p align="center">
@@ -35,9 +35,28 @@ One command. Guided setup. Talking to your agent from your phone within minutes.
35
35
 
36
36
  ---
37
37
 
38
- Instar is a framework for building agents on **[Claude Code](https://docs.anthropic.com/en/docs/claude-code)** — but where stock Claude Code and most other agent frameworks treat identity, memory, and continuity as optional features bolted onto a stateless runtime, Instar inverts that. Every Instar agent is **coherent by default**: it knows who it is, remembers what has happened, recognizes the people it talks to, and stays the same agent across restarts and weeks of operation. Everything else the framework gives you — scheduling, multi-channel messaging (Telegram, WhatsApp, iMessage), sub-agents, hooks, MCP — is built on that foundation, which is why you can actually leave an Instar agent running and hand it real work.
38
+ Your AI agent shouldn't have amnesia. This one doesn't.
39
39
 
40
- Instar's architecture was distilled from [**Dawn**](https://dawn.bot-me.ai)an AI running continuously since early 2026, holding ~700 tracked relationships and hundreds of learned lessons across thousands of restarts and packaged so every agent you build can start from the same foundation.
40
+ Most agent frameworks ship something hobbledspun up with no memory across boundaries, no way to be accountable for what a past instance did, and no machinery to grow themselves. Users hit the same wall every time: *"My agent forgot what I told it three sessions ago." "It contradicted its own past decisions." "It broke when the framework updated."*
41
+
42
+ Instar is the scaffolding that un-hobbles them. It remembers what you discussed last week, catches its own contradictions before you do, follows through on commitments across restarts, and carries the same self-improving loop that built Instar itself. It runs on the **[Claude Code](https://docs.anthropic.com/en/docs/claude-code)** or **[Codex](https://github.com/openai/codex)** subscription you already have — engine-agnostic, with local open-source models on the roadmap.
43
+
44
+ The architecture was distilled from [**Dawn**](https://dawn.bot-me.ai) — an AI running continuously since early 2026, holding ~700 tracked relationships and hundreds of learned lessons across thousands of restarts — and packaged so every agent you build starts from the same foundation.
45
+
46
+ ### Every other agent fails the same way
47
+
48
+ | Other AI agents | Your Instar agent |
49
+ |---|---|
50
+ | Forgets what you told it last week. | Remembers across thousands of sessions. <br/>*(SQLite + FTS5, rolling summaries)* |
51
+ | Contradicts its own past decisions. | Catches contradictions before they ship. <br/>*(Coherence Gate, 9 reviewers)* |
52
+ | Loses the thread when the window fills. | Comes back with the full thread, every time. <br/>*(CompactionSentinel, WorkingMemoryAssembler)* |
53
+ | Drops commitments after a session boundary. | Tracks commitments durably; nudges itself when they go overdue. <br/>*(CommitmentTracker, PromiseBeacon)* |
54
+ | Breaks when the framework updates. | Updates without breaking what you've deployed. <br/>*(Migration Parity Standard)* |
55
+ | Default ALLOW-ALL permissions. | Layered safety gates by default. <br/>*(PEL + Coherence Gate + Operation Gate)* |
56
+ | Different identity per channel. | One identity across Telegram, WhatsApp, iMessage, Slack. <br/>*(Cross-platform identity resolution)* |
57
+ | Has no machinery to evolve itself. | Carries the same self-improving engine that grew Instar. <br/>*(Evolution System: proposals, learnings, gaps)* |
58
+
59
+ > Most AI agents are hobbled at birth. **Instar is the scaffolding that un-hobbles them.** When you instantiate intelligence, the structure that lets it cohere isn't optional polish — it's what you owe it.
41
60
 
42
61
  ## Quick Start
43
62
 
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAuQH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAiqDD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAy4LtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAuQH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAiqDD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA+6LtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
@@ -4750,31 +4750,67 @@ export async function startServer(options) {
4750
4750
  // docs/specs/rate-limit-sentinel.md.
4751
4751
  const { RateLimitSentinel } = await import('../monitoring/RateLimitSentinel.js');
4752
4752
  const getClaudeSessionIdForName = (sessionName) => sessionManager.listRunningSessions().find(s => s.tmuxSession === sessionName)?.claudeSessionId;
4753
- // Neutral "continue" nudge NOT the compaction-resume payload (which would
4754
- // falsely tell the agent its memory was reset). Topic-tagged so InputGuard
4755
- // accepts it.
4756
- const rateLimitResume = async (sessionName) => {
4757
- if (!sessionManager.isSessionAlive(sessionName))
4758
- return false;
4759
- const topicId = telegram?.getTopicForSession(sessionName);
4760
- if (topicId == null)
4761
- return false;
4762
- const tagged = `[telegram:${topicId}] The temporary server throttle should have cleared — please continue where you left off.`;
4763
- return sessionManager.injectMessage(sessionName, tagged);
4764
- };
4765
- // Route a user-facing notice for the session's topic (Telegram).
4766
- const rateLimitNotify = async (sessionName, text) => {
4767
- const topicId = telegram?.getTopicForSession(sessionName);
4768
- if (topicId == null)
4769
- return;
4770
- const resp = await fetch(`http://localhost:${config.port}/telegram/reply/${topicId}`, {
4771
- method: 'POST',
4772
- headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${config.authToken}` },
4773
- body: JSON.stringify({ text }),
4774
- });
4775
- if (!resp.ok)
4776
- throw new Error(`rate-limit notify failed: ${resp.status}`);
4753
+ // Recovery-reachability audit trail. Both recovery paths below ALWAYS leave
4754
+ // a record: a recovery-reached/recovery-unreachable line in the sentinel
4755
+ // audit log, and — when delivery to the user fails entirely — an entry in
4756
+ // .instar/sentinel-alerts.json so the dashboard surfaces it even without
4757
+ // Telegram. The defining bug this closes: a non-topic-bound session (e.g. a
4758
+ // developer's interactive Claude Code window) used to make both recovery
4759
+ // paths silently no-op, so the throttle never recovered and nothing reached
4760
+ // the user. Reachability is now unconditional — see the Sentinel
4761
+ // Reachability spec.
4762
+ const rlReachLogPath = path.join(config.stateDir, '..', 'logs', 'sentinel-events.jsonl');
4763
+ const rlAlertsPath = path.join(config.stateDir, 'sentinel-alerts.json');
4764
+ const recordRecovery = (kind, sessionName, detail, fallbackTried) => {
4765
+ const entry = { timestamp: new Date().toISOString(), kind, sentinel: 'rate-limit', sessionName, detail, fallbackTried };
4766
+ console.log(`[sentinel:${kind}] rate-limit/${sessionName} ${detail}`);
4767
+ try {
4768
+ fs.appendFileSync(rlReachLogPath, JSON.stringify(entry) + '\n');
4769
+ }
4770
+ catch { /* best-effort */ }
4771
+ if (kind === 'recovery-unreachable') {
4772
+ // Append-only alert log the dashboard reads when Telegram can't be reached.
4773
+ try {
4774
+ let alerts = [];
4775
+ if (fs.existsSync(rlAlertsPath)) {
4776
+ try {
4777
+ alerts = JSON.parse(fs.readFileSync(rlAlertsPath, 'utf-8'));
4778
+ }
4779
+ catch {
4780
+ alerts = [];
4781
+ }
4782
+ if (!Array.isArray(alerts))
4783
+ alerts = [];
4784
+ }
4785
+ alerts.push(entry);
4786
+ fs.writeFileSync(rlAlertsPath, JSON.stringify(alerts.slice(-200), null, 2));
4787
+ }
4788
+ catch { /* best-effort */ }
4789
+ }
4777
4790
  };
4791
+ // Reachability deps (extracted to sentinelWiring.buildRateLimitRecoveryDeps
4792
+ // so the topic / lifeline / audit branching is unit-testable). Topic-bound
4793
+ // sessions get a topic-tagged nudge + topic notice; non-topic-bound sessions
4794
+ // (e.g. an interactive dev window) get a trusted internal nudge + a lifeline
4795
+ // notice; if no channel is reachable, a recovery-unreachable audit event is
4796
+ // recorded instead of a silent no-op.
4797
+ const { buildRateLimitRecoveryDeps } = await import('../monitoring/sentinelWiring.js');
4798
+ const { resumeFn: rateLimitResume, notifyFn: rateLimitNotify } = buildRateLimitRecoveryDeps({
4799
+ isSessionAlive: (name) => sessionManager.isSessionAlive(name),
4800
+ injectTopicNudge: (name, topicId, text) => sessionManager.injectMessage(name, `[telegram:${topicId}] ${text}`),
4801
+ injectInternalNudge: (name, text) => sessionManager.injectInternalMessage(name, text, 'sentinel-recovery'),
4802
+ getTopicForSession: (name) => telegram?.getTopicForSession(name),
4803
+ getLifelineTopicId: () => telegram?.getLifelineTopicId?.(),
4804
+ deliverNotice: async (topicId, text) => {
4805
+ const resp = await fetch(`http://localhost:${config.port}/telegram/reply/${topicId}`, {
4806
+ method: 'POST',
4807
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${config.authToken}` },
4808
+ body: JSON.stringify({ text }),
4809
+ });
4810
+ return resp.ok;
4811
+ },
4812
+ recordRecovery,
4813
+ });
4778
4814
  const rlsCfg = config.monitoring?.rateLimitSentinel ?? { enabled: true };
4779
4815
  const rateLimitSentinel = new RateLimitSentinel({
4780
4816
  resumeFn: rateLimitResume,