@nanhara/hara 0.121.1 → 0.122.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/CHANGELOG.md +120 -0
- package/README.md +57 -10
- package/SECURITY.md +48 -9
- package/dist/agent/loop.js +169 -31
- package/dist/agent/reminders.js +22 -7
- package/dist/agent/repeat-guard.js +26 -7
- package/dist/agent/structured.js +231 -0
- package/dist/agent/touched.js +24 -6
- package/dist/checkpoints.js +103 -17
- package/dist/cli.js +16 -0
- package/dist/config.js +173 -34
- package/dist/context/agents-md.js +44 -9
- package/dist/context/mentions.js +10 -4
- package/dist/context/subdir-hints.js +40 -7
- package/dist/cron/deliver.js +37 -3
- package/dist/cron/runner.js +372 -37
- package/dist/cron/store.js +11 -3
- package/dist/exec/jobs.js +88 -20
- package/dist/feedback.js +3 -2
- package/dist/fs-read.js +421 -12
- package/dist/fs-walk.js +8 -2
- package/dist/fs-write.js +433 -21
- package/dist/gateway/dingtalk.js +4 -1
- package/dist/gateway/discord.js +53 -20
- package/dist/gateway/feishu.js +157 -58
- package/dist/gateway/flows-pending.js +727 -0
- package/dist/gateway/flows.js +391 -16
- package/dist/gateway/matrix.js +81 -18
- package/dist/gateway/mattermost.js +44 -34
- package/dist/gateway/media.js +659 -0
- package/dist/gateway/outbound-files.js +379 -0
- package/dist/gateway/serve.js +712 -169
- package/dist/gateway/sessions.js +475 -78
- package/dist/gateway/signal.js +31 -28
- package/dist/gateway/slack.js +28 -21
- package/dist/gateway/telegram.js +33 -21
- package/dist/gateway/tmux-routes.js +11 -3
- package/dist/gateway/wecom.js +38 -31
- package/dist/gateway/weixin.js +147 -59
- package/dist/hooks.js +41 -23
- package/dist/index.js +763 -273
- package/dist/mcp/client.js +164 -12
- package/dist/memory/store.js +68 -22
- package/dist/org/planner.js +36 -10
- package/dist/org/projects.js +347 -0
- package/dist/org/review-chain.js +360 -24
- package/dist/org/roles.js +42 -13
- package/dist/profile/profile.js +152 -27
- package/dist/recall.js +4 -2
- package/dist/runtime.js +37 -0
- package/dist/sandbox.js +142 -33
- package/dist/search/semindex.js +182 -53
- package/dist/search/zvec-store.js +121 -42
- package/dist/security/permissions.js +326 -19
- package/dist/security/private-state.js +299 -0
- package/dist/security/project-trust.js +6 -0
- package/dist/security/secrets.js +84 -9
- package/dist/security/sensitive-files.js +723 -0
- package/dist/security/subprocess-env.js +210 -0
- package/dist/serve/server.js +774 -318
- package/dist/serve/sessions.js +113 -33
- package/dist/session/store.js +298 -47
- package/dist/skills/skills.js +16 -7
- package/dist/tools/all.js +1 -0
- package/dist/tools/builtin.js +77 -49
- package/dist/tools/codebase.js +3 -1
- package/dist/tools/computer.js +98 -92
- package/dist/tools/cron.js +6 -0
- package/dist/tools/edit.js +22 -9
- package/dist/tools/external_agent.js +110 -16
- package/dist/tools/memory.js +38 -8
- package/dist/tools/patch.js +253 -34
- package/dist/tools/search.js +543 -73
- package/dist/tools/send.js +11 -5
- package/dist/tools/task.js +453 -0
- package/dist/tools/todo.js +67 -16
- package/dist/tools/web.js +168 -54
- package/dist/undo.js +83 -7
- package/package.json +11 -10
- package/runtime-bootstrap.cjs +72 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,126 @@ All notable changes to `@nanhara/hara`.
|
|
|
5
5
|
> Versioning (pre-1.0, SemVer-style): the **minor** (middle) number bumps for a **new feature**; the
|
|
6
6
|
> **patch** (last) number bumps for **optimizations/fixes of existing features**.
|
|
7
7
|
|
|
8
|
+
## 0.122.1 — 2026-07-14 — protected files and explicit extension trust
|
|
9
|
+
|
|
10
|
+
- **The npm CLI now requires Node.js 22.12+.** Node 20 is end-of-life, so Hara no longer makes a security or
|
|
11
|
+
compatibility promise for it. npm metadata, `hara doctor`, and startup diagnostics now agree; an older
|
|
12
|
+
runtime exits with a direct `nvm install 22 && nvm use 22` upgrade hint. Standalone binaries and Desktop
|
|
13
|
+
sidecars remain self-contained and do not require a host Node installation.
|
|
14
|
+
- **Built-in file access fails closed before ordinary approval/dispatch.** Canonical and real-path checks
|
|
15
|
+
reject `.env`/`.env.*`, credential stores, private keys, and private Hara runtime state in file reads,
|
|
16
|
+
edit/patch pre-reads, grep/glob/ls, `@file`/completion, codebase and stale semantic indexes, checkpoints,
|
|
17
|
+
gateway file delivery, and cron command admission. Safe templates such as `.env.example`, `.env.sample`,
|
|
18
|
+
and `.env.template` remain readable. `HARA_ALLOW_SENSITIVE_FILES=1` is an explicit launch-time exposure
|
|
19
|
+
switch for one process; it removes both these built-in denies and that process's shell protected-read mask.
|
|
20
|
+
- **Shell protection now reflects the host's guarantees.** Tool subprocesses receive a scrubbed environment;
|
|
21
|
+
inherited variables can be explicitly retained with the launch-time `HARA_SUBPROCESS_ENV_ALLOW` list, and
|
|
22
|
+
output is redacted by secret pattern and exact inherited value. Under the default protected-file policy,
|
|
23
|
+
shell admission blocks literal protected paths and environment dump commands on every platform. macOS
|
|
24
|
+
additionally applies a Seatbelt read mask to existing protected
|
|
25
|
+
files/directories, even when the general write sandbox is off. Linux and Windows do not have that kernel
|
|
26
|
+
read mask: their arbitrary shell code is not a security sandbox and static preflight can be bypassed.
|
|
27
|
+
- **MCP servers and external coding agents are explicit trusted extensions.** They execute outside Hara's
|
|
28
|
+
protected-file boundary, require confirmation on every interactive tool call (including `full-auto`), and
|
|
29
|
+
are disabled in non-interactive runs by default. Reviewed automation may opt in before launch with
|
|
30
|
+
`HARA_ALLOW_TRUSTED_EXTENSIONS=1`; inherited credentials are still scrubbed.
|
|
31
|
+
- **Repositories no longer silently control Hara's privileged configuration.** Project config is limited by
|
|
32
|
+
default to validated presentation/model preferences; provider routes, credentials, hooks, MCP, sandbox,
|
|
33
|
+
guardian, approval, and automation settings require the launch-time `HARA_TRUST_PROJECT_CONFIG=1` opt-in.
|
|
34
|
+
Project permissions may tighten global policy but cannot grant new access, and Git-tracked `.hara-profile`
|
|
35
|
+
pins are ignored unless that same trust decision was made before startup. Symlink, hard-link, size, identity,
|
|
36
|
+
and concurrent-change checks protect each of these inputs, while diagnostics reveal key names but no values.
|
|
37
|
+
- **Coding and project-state writes are transactional.** Edit, patch, undo, memory, skills, plans, profiles,
|
|
38
|
+
indexes, and gateway state use no-follow descriptors, inode checks, bounded reads, atomic replace or
|
|
39
|
+
compare-and-swap semantics, and private modes where appropriate. Protected search uses the same verified
|
|
40
|
+
descriptor path instead of handing sensitive-path decisions to `rg`, closing replacement and hard-link
|
|
41
|
+
races. `AGENTS.md`, subdirectory hints, mentions, and touched-file recall are bounded and reject protected
|
|
42
|
+
aliases before adding repository content to model context.
|
|
43
|
+
- **Semantic search and review automation distrust stale or historical content.** Semantic indexes carry a
|
|
44
|
+
versioned manifest with content hashes and are rebuilt when source identity or bytes change. Review-chain
|
|
45
|
+
prompts receive bounded status/path metadata rather than Git patches; an auto-commit proceeds only when the
|
|
46
|
+
staged blob still matches the verified worktree descriptor, including deletion and SHA-256 repository edge
|
|
47
|
+
cases. Read-only auto-run Git policy excludes commands that can expose historical blobs, credentials, remote
|
|
48
|
+
URLs, or patch bodies.
|
|
49
|
+
- **Old private state is tightened and stale checkpoint history is rotated.** Startup repairs `~/.hara` and
|
|
50
|
+
sensitive runtime trees to owner-only modes on POSIX systems. The protected checkpoint format rebuilds old
|
|
51
|
+
derived shadow repositories, filters protected paths independently of the launch-time exposure switch, and
|
|
52
|
+
purges a checkpoint repository if a protected blob ever reaches its index.
|
|
53
|
+
- **Long-running work has bounded ownership and shutdown.** Shell jobs, external agents, gateway children,
|
|
54
|
+
approved organization flows, and cron commands terminate the whole process tree with TERM-to-KILL escalation
|
|
55
|
+
and stop accepting output after cancellation. Background job counts, cron run time/log size, lock takeover,
|
|
56
|
+
and context fan-out are capped; Windows shell aliases and environment-dump variants are denied consistently.
|
|
57
|
+
- **Gateway outbound files are immutable after admission.** Telegram, Feishu, Slack, Discord, Mattermost,
|
|
58
|
+
Matrix, WeCom, and Weixin upload verified in-memory bytes plus a safe filename, so a queued path cannot be
|
|
59
|
+
swapped for a secret before delivery. Counts and bytes are bounded at queue and consume time, cleanup checks
|
|
60
|
+
inode identity, and Signal outbound files fail closed because its RPC accepts only reopenable filesystem paths.
|
|
61
|
+
|
|
62
|
+
## 0.122.0 — 2026-07-13 — structured runs, durable work, and a fail-closed gateway
|
|
63
|
+
|
|
64
|
+
- **Machine-safe headless runs.** `hara -p … --schema <json|file>` installs a run-scoped
|
|
65
|
+
`structured_output` contract, validates the value against JSON Schema, and writes exactly one JSON value to
|
|
66
|
+
stdout. Prose, auth notices, retries, and provider/schema failures cannot masquerade as machine output:
|
|
67
|
+
diagnostics go to stderr and failures exit non-zero. `hara -p … --role <id>` now applies the role's persona,
|
|
68
|
+
model, and allow/deny tool policy instead of changing the prompt alone.
|
|
69
|
+
- **Agents have stable homes.** `hara projects add/list/remove` maintains a private, atomic registry of project
|
|
70
|
+
homes; `hara agents` builds one address book from global and registered-project roles.
|
|
71
|
+
`hara org --role project:agent …` resolves unambiguously and executes at that home with its project context/config. Concurrent
|
|
72
|
+
CLIs safely share the registry, and dead lock owners can be reclaimed without stealing a live lock.
|
|
73
|
+
- **Two levels of work state.** `todo_write` is now isolated per interactive/headless/sub-agent/serve session
|
|
74
|
+
and persists with the session, so concurrent agents cannot overwrite each other's checklist. The new `task`
|
|
75
|
+
tool is a durable cross-session project pool with owners, statuses, `blockedBy` dependencies, cycle checks,
|
|
76
|
+
and private atomic cross-process persistence. `hara serve` exposes the pool through `tasks.list`.
|
|
77
|
+
- **10-platform gateway, with project-agent roaming.** Telegram, WeChat, Discord, Feishu/Lark, Slack,
|
|
78
|
+
Mattermost, Matrix, DingTalk, WeCom, and Signal adapters now classify direct vs multi-party chats
|
|
79
|
+
conservatively. The full coding agent accepts only verified private messages; unknown channel shapes fail
|
|
80
|
+
closed. `/agent <name|project:name>` pins a thread to an indexed agent and its home, while `/agent main`
|
|
81
|
+
restores the prior project thread. Chat/session preferences survive project round-trips and group-member
|
|
82
|
+
state is isolated.
|
|
83
|
+
- **Untrusted group flows cannot reach coding tools.** Opt-in `~/.hara/flows.json` rules are hot-reloaded and
|
|
84
|
+
evaluated through a bounded, stateless provider call with `tools: []` — no shell, files, MCP, session, or
|
|
85
|
+
project context. Rules support trigger filters, JSON Schema, disposition-based notification/auto-reply,
|
|
86
|
+
redacted rotating logs, and rate/concurrency caps. Proposed sends and agent dispatches are parked unless an
|
|
87
|
+
explicitly configured safe `replyOn` disposition applies.
|
|
88
|
+
- **Single-owner, idempotent approvals.** Consequential flow actions require a unique allowlisted owner and a
|
|
89
|
+
verified private channel. Deterministic `/approve <id>`, `/edit <id> <content>`, and `/reject <id>` commands
|
|
90
|
+
avoid “latest draft” ambiguity; blank edits fail closed. Pending actions use private atomic storage and a
|
|
91
|
+
compare-and-set execution claim, shared by chat and the new serve `approvals.list/resolve` inbox, so two
|
|
92
|
+
approval surfaces cannot double-send. Deferred actions are parked only for one-shot delivery targets
|
|
93
|
+
(Telegram, Feishu/Lark, or WeChat); other adapters fail closed instead of presenting an unusable approval.
|
|
94
|
+
- **Bounded gateway execution and media.** Turns are FIFO per session (depth 8), with four active children,
|
|
95
|
+
bounded global/session-key backlogs, a 15-minute default/30-minute hard timeout, and TERM-to-KILL shutdown;
|
|
96
|
+
non-zero or signalled children fail visibly. Inbound attachments are authorized before download, limited to
|
|
97
|
+
four files and 20 MiB each, streamed into private random paths with time/concurrency/retention quotas, and
|
|
98
|
+
expired after 24 hours. Progress markers are recalled in `finally`, gateway chat/session files are `0600`
|
|
99
|
+
with lock-before-load persistence, and ambiguous/stale locks are never reclaimed merely by age.
|
|
100
|
+
- **Layered flow admission.** Group classifiers are capped globally (20/minute, 120/hour), per rule/platform/chat
|
|
101
|
+
(10/minute, 60/hour), per sender (5/minute), and at four active runs. Rate maps and key sizes are bounded and
|
|
102
|
+
saturation fails closed, so rotating identities cannot grow memory or bypass the host-wide ceiling.
|
|
103
|
+
- **Live config for persistent clients.** `hara serve` rebuilds cwd-specific provider routes, credentials, and
|
|
104
|
+
guardian settings on sessions/turns; `initialize`, `models.list`, and new sessions reflect current defaults.
|
|
105
|
+
Resumed sessions retain their explicit model pin while using the live provider route, so credential rotation
|
|
106
|
+
and project config edits no longer require a server restart.
|
|
107
|
+
- **Coding-path robustness.** File reads/search/edit/patch now reject FIFOs/devices and symlink races, cap reads,
|
|
108
|
+
use bounded subprocess search with a linear glob matcher, preserve exact file modes, and roll back multi-file
|
|
109
|
+
patches without overwriting concurrent replacements; writes move-claim the expected inode and commit with
|
|
110
|
+
create-if-absent semantics, while `/undo` applies the same identity checks. Blank
|
|
111
|
+
project/env routing values no longer mask valid global config; precedence is environment > project > overlay
|
|
112
|
+
> global. Web fetch/search blocks IPv4-mapped and full link-local IPv6 SSRF forms and tries regional providers
|
|
113
|
+
sequentially instead of broadcasting a successful query. Package installs stay attached with bounded
|
|
114
|
+
long-operation timeouts, tunnel commands preflight their binaries, TUI resize repaints reliably, persisted/
|
|
115
|
+
public text redacts secrets, and session writes are private, atomic, and cross-process safe.
|
|
116
|
+
- **Interrupts and non-interactive outcomes are honest.** Cancelling a parallel tool round records matching
|
|
117
|
+
interrupted results while preserving completed side effects; serve approvals settle immediately on interrupt.
|
|
118
|
+
The stream-stall watchdog is a hard Promise boundary even when a provider ignores its abort signal.
|
|
119
|
+
Headless and org runs now exit non-zero on provider errors, empty/halted turns, schema failures, and rejected
|
|
120
|
+
reviews; plan atoms stop on the same outcomes instead of being verified as done, and failed implementers are
|
|
121
|
+
never committed. Read-only roles are resolved before startup and launch neither hooks nor configured/plugin
|
|
122
|
+
MCP subprocesses.
|
|
123
|
+
- **Private serve lifecycle.** `~/.hara`/`serve.json` are tightened to `0700`/`0600` and discovery is fsynced,
|
|
124
|
+
atomically replaced without following symlinks, and removed only by its owning instance. Discovery failures
|
|
125
|
+
close the listening socket. Serve-side compaction is mutually exclusive with turns/config changes, carries an
|
|
126
|
+
abort signal, releases locks on interrupt/shutdown, and has a 60-second hard deadline.
|
|
127
|
+
|
|
8
128
|
## 0.121.1 — field-feedback reliability & credential safety
|
|
9
129
|
|
|
10
130
|
- **Terminal resize no longer erases the composer.** Hara clears stale Ink output only before a real
|
package/README.md
CHANGED
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
|
|
13
13
|
**Highlights**
|
|
14
14
|
- **An org, not just an agent** — `hara org "<task>"` routes work to the role that *owns* it; `hara plan "<task>"` decomposes a task into a verified DAG of atoms (frame → atomize → sequence → execute → **verify gate**), and `hara plan --parallel` runs independent atoms concurrently.
|
|
15
|
-
- **Drive it from chat** — `hara gateway` runs your local hara from **Telegram · WeChat · Discord · Feishu/Lark · Slack · Mattermost · Matrix · DingTalk · WeCom · Signal** (10 platforms), with **two-way images
|
|
15
|
+
- **Drive it from chat** — `hara gateway` runs your local hara from **Telegram · WeChat · Discord · Feishu/Lark · Slack · Mattermost · Matrix · DingTalk · WeCom · Signal** (10 platforms), with **two-way images where the platform has a byte-upload API**, resumable per-chat sessions, project/agent roaming, bounded per-thread queues, and approval-gated group automations. Connects out — no public webhook. See **[docs/gateway.md](docs/gateway.md)**.
|
|
16
16
|
- **Real terminal UX** — an **ink TUI**: bottom-pinned input box, **plan mode** (read-only investigation → the model submits its plan via `exit_plan` → approve → execute), selectable approvals with "don't ask again", windowed reasoning, **paste images** (Ctrl+V) for vision models, light/dark theme.
|
|
17
17
|
- **Persistent memory + self-evolution** — `memory_*` tools over global/project `MEMORY.md`; the agent recalls before acting, **proactively saves** durable facts, and grows its own playbooks (a lexical guard screens what it writes). Inspect/consolidate it with **`hara memory show`** and **`hara memory distill`** (promote recent daily logs → durable memory). Lexical-first by design — semantic search is opt-in, never required.
|
|
18
18
|
- **Multi-provider, all streamed** — Anthropic (Claude) or any OpenAI-compatible endpoint (Qwen/DashScope, GLM, Kimi, OpenAI) with live Markdown + visible reasoning.
|
|
19
|
-
- **Delegate to other agents** — the **`external_agent`** tool hands a self-contained task to **Claude Code** or **Codex** running headless, and returns the result — so you pick the best engine per task.
|
|
19
|
+
- **Delegate to other agents** — the **`external_agent`** tool hands a self-contained task to **Claude Code** or **Codex** running headless, and returns the result — so you pick the best engine per task. It is a trusted extension outside Hara's protected-file boundary: every interactive call requires confirmation, and non-interactive use is disabled by default.
|
|
20
20
|
- **Honest under a slow network** — a live "waiting for the model… Ns" status, a stall watchdog that
|
|
21
21
|
auto-fails-over instead of hanging, big pastes folding to a token, and a startup update notice — the
|
|
22
22
|
terminal never feels dead.
|
|
@@ -26,6 +26,9 @@ Track it: https://github.com/hara-cli/hara · https://hara.run
|
|
|
26
26
|
|
|
27
27
|
## Install
|
|
28
28
|
|
|
29
|
+
The npm package requires **Node.js 22.12 or newer**. If needed, upgrade first with
|
|
30
|
+
`nvm install 22 && nvm use 22`. Node.js 20 is end-of-life and is not a supported Hara runtime.
|
|
31
|
+
|
|
29
32
|
```bash
|
|
30
33
|
npm i -g @nanhara/hara
|
|
31
34
|
```
|
|
@@ -135,8 +138,16 @@ hara expresses it the way each endpoint wants (OpenAI `reasoning_effort`, Anthro
|
|
|
135
138
|
DashScope `enable_thinking`, **DeepSeek** V4 `thinking` + `reasoning_effort` where `max` genuinely raises the
|
|
136
139
|
effort). In the TUI, bare `/model` opens a picker — ↑↓ pick a model, **←→ set the thinking level**.
|
|
137
140
|
|
|
138
|
-
Config lives in `~/.hara/config.json`.
|
|
139
|
-
`
|
|
141
|
+
Config lives in `~/.hara/config.json`; the nearest project `.hara/config.json` may set the explicitly safe
|
|
142
|
+
project preferences `model`, `theme`, `vimMode`, `autoCompact`, and `reasoningEffort`. Repository config is
|
|
143
|
+
untrusted by default: routing/credential, hook/MCP, approval/sandbox, computer-control, and other privileged
|
|
144
|
+
keys are ignored with a key-name-only warning. For a repository you have reviewed, launch with
|
|
145
|
+
`HARA_TRUST_PROJECT_CONFIG=1` to enable all of its project keys for that process. The opt-in is captured at
|
|
146
|
+
startup, and project config itself must be a bounded regular file under a real (non-symlink) `.hara` directory.
|
|
147
|
+
Effective precedence for enabled keys is **environment > project > selected overlay > global**. Empty routing
|
|
148
|
+
values are ignored, so an empty project/env value cannot hide a working global credential or endpoint. Env overrides include
|
|
149
|
+
`HARA_PROVIDER`, `HARA_MODEL`, `HARA_BASE_URL`, `HARA_API_KEY`, and the provider key
|
|
150
|
+
(`ANTHROPIC_API_KEY` / `DASHSCOPE_API_KEY`).
|
|
140
151
|
|
|
141
152
|
## Use
|
|
142
153
|
|
|
@@ -146,12 +157,17 @@ hara init # analyze the project & (re)generate AGENTS.md
|
|
|
146
157
|
hara doctor # check your setup (auth / model / node / assets / roles)
|
|
147
158
|
hara roles init # scaffold role-agents (implementer / reviewer / docs)
|
|
148
159
|
hara org "review src/ for bugs" # dispatch a task to the role that owns it (or --role <id>)
|
|
160
|
+
hara projects add shop /absolute/path/to/shop # register an agent home
|
|
161
|
+
hara agents # list global + registered project agents
|
|
162
|
+
hara org --role shop:reviewer "audit auth" # run that agent at its own home
|
|
149
163
|
hara plan "add a /health endpoint with a test" # decompose → sequence (DAG) → run each step + verify
|
|
150
164
|
hara plan --parallel "..." # run independent atoms concurrently · hara plan resume # continue a stopped plan
|
|
151
165
|
hara review # review uncommitted changes for bugs/security/missing tests (--staged · --base main)
|
|
152
166
|
hara commit # AI commit message from staged changes, then commit (-a to stage all · -y to skip confirm)
|
|
153
167
|
hara index # build the semantic search index (after: hara config set embedProvider ollama|qwen)
|
|
154
168
|
hara -p "summarize @README.md and fix the lint errors in src/" # one-shot; @path attaches a file
|
|
169
|
+
hara -p "extract package metadata" --schema ./schema.json # stdout is exactly schema-valid JSON
|
|
170
|
+
hara -p "review the current diff" --role reviewer # persona + model + tool policy from the role
|
|
155
171
|
hara --approval auto-edit # suggest (default) | auto-edit | full-auto (-y = full-auto)
|
|
156
172
|
hara --sandbox workspace-write # confine shell writes to the project (macOS Seatbelt)
|
|
157
173
|
hara -c # resume the most recent session in this directory
|
|
@@ -159,6 +175,12 @@ hara --profile work # use a named profile from ~/.hara/config.json
|
|
|
159
175
|
hara -m glm-5 # pick a model
|
|
160
176
|
```
|
|
161
177
|
|
|
178
|
+
For automation, `--schema` accepts inline JSON Schema or a schema file. The model must return through the
|
|
179
|
+
validated `structured_output` tool; on success stdout contains only the JSON value, while diagnostics go to
|
|
180
|
+
stderr and missing/invalid output exits non-zero. `--role reviewer` resolves locally, `--role global:reviewer`
|
|
181
|
+
uses the portable global persona in the current project, and `--role shop:reviewer` runs at that registered
|
|
182
|
+
project home. Each form enforces the role's persona, model, `allowTools`/`denyTools`, and `readOnly` policy.
|
|
183
|
+
|
|
162
184
|
Inside the REPL: `/help` `/init` `/tools` `/model` `/approval` `/org` `/plan` `/roles` `/usage` `/doctor` `/sessions` `/undo` `/compact` `/recall` `/reset` `/exit` (type `/`+Tab to complete). Type `@` + Tab to attach a file (fuzzy, walks subdirectories).
|
|
163
185
|
|
|
164
186
|
The interactive REPL is an **ink TUI**: a bordered **input box pinned at the bottom** — session name in
|
|
@@ -206,19 +228,37 @@ vector DB needed, and lexical still works when there's no index. Re-running `har
|
|
|
206
228
|
only changed files re-embed (a full repo rebuild that takes ~a minute re-runs in well under a second).
|
|
207
229
|
|
|
208
230
|
**Approval modes**: `suggest` confirms edits & shell · `auto-edit` auto-applies file edits but confirms shell · `full-auto` runs everything.
|
|
209
|
-
**
|
|
231
|
+
**Protected files and shell sandboxing**: built-in file, search, and context paths hard-reject `.env`/credential/private-key/private-Hara-state files before the ordinary approval/dispatch path can authorize them. Safe templates (`.env.example`, `.env.sample`, `.env.template`) remain readable. `HARA_ALLOW_SENSITIVE_FILES=1` is an explicit one-process exposure switch: it removes these built-in denies and that process's shell protected-read mask. Shell subprocesses receive a scrubbed environment; explicitly retain a named inherited variable with `HARA_SUBPROCESS_ENV_ALLOW=NAME[,NAME]` (output is still redacted). With the protected-file policy enabled, shell preflight rejects literal protected paths and environment-dump commands on every OS. On macOS, Seatbelt also masks existing protected files/directories from the shell and `--sandbox workspace-write|read-only` provides **file-write confinement**. Linux/Windows have no equivalent kernel read mask: static shell preflight is a useful guardrail, not a security sandbox, and arbitrary code can bypass it.
|
|
210
232
|
**Screen control** (opt-in): the `computer` tool drives desktop software (screenshot → click/type), native per OS
|
|
211
233
|
(mac `screencapture`+`cliclick` · Windows PowerShell · Linux `scrot`+`xdotool`). Off by default — enable a tier with
|
|
212
234
|
`hara config set computerUse read|click|full` and allowlist apps with `hara config set computerApps "App, …"`. Guarded
|
|
213
235
|
by the tier, the frontmost-app allowlist, a dangerous-key blocklist, and a once-per-session grant. Screenshots are read via your
|
|
214
236
|
vision model into **actionable** output — interactive elements + positions (pass `focus` to target what you're after) — so even a text-only main model can click.
|
|
215
237
|
**Sessions**: conversations are saved automatically — `-c` / `--resume <id>` to continue, `hara sessions` to list, `hara export [id] [--out file]` to render one as a Markdown transcript.
|
|
216
|
-
**MCP**: add an `mcpServers` map to config (
|
|
238
|
+
**MCP**: add an `mcpServers` map to global config (a reviewed project config additionally needs `HARA_TRUST_PROJECT_CONFIG=1` at launch); their tools appear to the agent as `mcp__<server>__<tool>`. Configured MCP servers, like `external_agent`, are trusted host extensions outside Hara's protected-file boundary. Every interactive tool call requires confirmation (even in `full-auto`), and non-interactive runs disable them by default; reviewed automation can explicitly opt in before launch with `HARA_ALLOW_TRUSTED_EXTENSIONS=1`. hara can also **be** an MCP server — `hara mcp` exposes its read/search tools (esp. **`codebase_search`**) over stdio so other clients (Claude Desktop, Cursor, another hara) can use them; read-only by default (`HARA_MCP_TOOLS` to override).
|
|
217
239
|
**Vim mode**: `hara config set vimMode true` makes the prompt modal — Esc → normal, `i/a/A/I` insert, `h l 0 $ w b e` motions, `x D C dd cw p` edits. Off by default.
|
|
218
240
|
**Scheduled tasks**: `hara cron add "0 9 * * 1-5" "<task>"` (or `"every 30m"`, `"in 2h"`) runs a task on a schedule — each run is a fresh hara session. `hara cron install` wires a per-minute tick into launchd/crontab (no daemon); `--org` routes through the role org. Manage with `hara cron list/run/enable/disable/remove/logs`.
|
|
241
|
+
**Work coordination**: `todo_write` is the agent's short, session-scoped checklist; it persists with that
|
|
242
|
+
session and is isolated between simultaneous sub-agents and serve sessions. `task` is the durable project pool
|
|
243
|
+
for work that outlives a conversation: add/update/list/remove items with `pending|in_progress|done`, an optional
|
|
244
|
+
owner, and `blockedBy` dependencies. The private, atomic store is shared by concurrent hara processes for the
|
|
245
|
+
same project and rejects missing/self/cyclic dependencies.
|
|
219
246
|
**Notifications**: `hara config set notify bell` (terminal bell) or `notify system` (OS notification) pings you when a turn finishes — handy for long runs you've stepped away from. Gated on elapsed time so quick turns stay quiet; off by default.
|
|
220
|
-
**Hooks**: run your own shell commands around tool calls via a `"hooks"` map in config. A **`PreToolUse`** hook can **veto** a call (non-zero exit blocks it; its output becomes the reason the model sees) — gate `bash`, forbid edits outside a path, require a clean tree. A **`PostToolUse`** hook observes (format/lint a file the agent just wrote, log, notify). Each has a `matcher` (regex/literal on the tool name, `*` = all) and gets `{tool, payload}` on stdin + `HARA_TOOL_NAME` in env. Plugins can contribute hooks too.
|
|
221
|
-
|
|
247
|
+
**Hooks**: run your own shell commands around tool calls via a `"hooks"` map in global config; hooks from a reviewed project config require the launch-time `HARA_TRUST_PROJECT_CONFIG=1` opt-in. A **`PreToolUse`** hook can **veto** a call (non-zero exit blocks it; its output becomes the reason the model sees) — gate `bash`, forbid edits outside a path, require a clean tree. A **`PostToolUse`** hook observes (format/lint a file the agent just wrote, log, notify). Each has a `matcher` (regex/literal on the tool name, `*` = all) and gets `{tool, payload}` on stdin + `HARA_TOOL_NAME` in env. Plugins can contribute hooks too.
|
|
248
|
+
Reviewer/read-only/plan runs and parallel read-only sub-agents suppress both hook phases: PreToolUse and
|
|
249
|
+
PostToolUse commands are arbitrary shell, so either could otherwise bypass their read-only contract indirectly.
|
|
250
|
+
They also skip configured and plugin-provided MCP server processes, so starting an external tool server cannot
|
|
251
|
+
bypass the same contract before the first model turn.
|
|
252
|
+
**Profiles and live config**: select an identity with `--profile <name>`; use `overlays` in
|
|
253
|
+
`~/.hara/config.json` for named config overlays. Project `.hara/config.json` files get the safe preference
|
|
254
|
+
allowlist above; project-specific routing requires `HARA_TRUST_PROJECT_CONFIG=1` before launch.
|
|
255
|
+
`.hara-profile` identity pins are read no-follow with size, single-inode, and hard-link checks; pin updates use
|
|
256
|
+
an atomic compare-and-swap, and invalid-pin warnings never echo file contents or paths. A Git-tracked pin is
|
|
257
|
+
repository-controlled and ignored by default; local untracked pins created with `hara profile pin` work
|
|
258
|
+
normally. The same launch-time `HARA_TRUST_PROJECT_CONFIG=1` opt-in enables a reviewed tracked pin.
|
|
259
|
+
Long-lived `hara serve` processes reload provider credentials/routes and guardian settings for the target cwd on
|
|
260
|
+
new sessions and turns. `models.list` and new sessions see current defaults; a resumed session keeps its explicit
|
|
261
|
+
model pin while using the live provider route. No server restart is required after a credential rotation.
|
|
222
262
|
|
|
223
263
|
### The org — what makes hara different
|
|
224
264
|
|
|
@@ -234,6 +274,13 @@ to a clean start tree; a review that doesn't pass leaves the work uncommitted).
|
|
|
234
274
|
**`agent`** tool spawns **parallel read-only sub-agents** for fan-out — analyze / review / search
|
|
235
275
|
several things at once (each can take a `role`), bounded to 8 concurrent (`HARA_MAX_CONCURRENCY`).
|
|
236
276
|
|
|
277
|
+
Register project homes with `hara projects add <name> <absolute-path>`, then `hara agents` becomes a global
|
|
278
|
+
address book across `~/.hara/roles` and each registered project's roles. A qualified address such as
|
|
279
|
+
`shop:reviewer` is unambiguous; both `hara org --role shop:reviewer "<task>"` and one-shot `hara -p "<task>"
|
|
280
|
+
--role shop:reviewer` execute at that agent's home, with its own `AGENTS.md`, live project config, role model,
|
|
281
|
+
and allow/deny/read-only tool policy. `global:<name>` is portable and runs in the current project. A bare name
|
|
282
|
+
uses the local role first and otherwise must resolve unambiguously.
|
|
283
|
+
|
|
237
284
|
Beyond routing, **`hara plan "<task>"`** makes the org *plan*: it decomposes the task into atoms,
|
|
238
285
|
sequences them as a DAG, and executes each step (optionally routed to a role) behind a per-step
|
|
239
286
|
**verify gate** — frame → atomize → sequence → execute → verify. Each atom may carry a `check` shell
|
|
@@ -255,11 +302,11 @@ turn, or **`/undo`** to revert the last edit. In-session **`/diff`**, **`/review
|
|
|
255
302
|
- **Project context**: auto-loads `AGENTS.md` (the cross-tool standard) walking up to the repo root; `hara init` writes one by analyzing the repo.
|
|
256
303
|
- **`@file` mentions**: attach file contents to a message (`@path`); Tab-completes with a **fuzzy** matcher over the project (subdirs, git-tracked + untracked) — `@idx` → `src/index.ts`. `@<dir>` loads a directory listing, `@src/`+Tab drills into a folder, and mistyped tool/file paths get a "did you mean" suggestion.
|
|
257
304
|
- **Multi-provider**: Anthropic (Claude) or any OpenAI-compatible endpoint (Qwen/DashScope, GLM, Kimi, OpenAI) — **all streamed live**.
|
|
258
|
-
- **Chat gateway**: drive your local hara from
|
|
305
|
+
- **Chat gateway**: drive your local hara from **Telegram · WeChat · Discord · Feishu/Lark · Slack · Mattermost · Matrix · DingTalk · WeCom · Signal**. The daemon connects out (no public webhook), with per-chat sessions, project roaming (`/cd`), agent switching (`/agent`), and **two-way images on byte-upload-capable platforms**. Setup, platform capability details, and the group-flow security model: **[docs/gateway.md](docs/gateway.md)**.
|
|
259
306
|
|
|
260
307
|
### Roadmap
|
|
261
308
|
|
|
262
|
-
**Shipped:** ink TUI · plan mode · persistent memory + self-evolution · atomization planner · parallel plan atoms · **multi-role review chains** · parallel sub-agents · MCP client *and* server · **scheduled tasks (`hara cron`)** · **chat gateway (
|
|
309
|
+
**Shipped:** ink TUI · plan mode · persistent memory + self-evolution · atomization planner · parallel plan atoms · **multi-role review chains** · global project-agent index · durable project tasks · parallel sub-agents · MCP client *and* server · **scheduled tasks (`hara cron`)** · **chat gateway (10 platforms, capability-aware media)** · **single-binary distribution** · **Docker image** · `/compact` context management.
|
|
263
310
|
**Next:** SSOT data authority · an enterprise control-plane (fleet + central token management).
|
|
264
311
|
|
|
265
312
|
## Security
|
package/SECURITY.md
CHANGED
|
@@ -29,9 +29,45 @@ local user (who already has your shell).
|
|
|
29
29
|
- **`web_fetch` SSRF guard.** Refuses to fetch private / loopback / link-local / CGNAT addresses (resolving
|
|
30
30
|
the hostname first), re-checks on every redirect hop, and reads the body under a byte ceiling — so the
|
|
31
31
|
model can't reach cloud-metadata endpoints or internal services.
|
|
32
|
-
- **
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
- **Protected reads in built-in paths.** `.env`, `.env.*` (except explicit templates such as
|
|
33
|
+
`.env.example`), credential stores, private keys, and private Hara state are rejected before the ordinary
|
|
34
|
+
approval/dispatch path can authorize them. The same canonical/real-path check covers built-in file reads,
|
|
35
|
+
edit/patch pre-reads, grep/glob/ls, `@file`, completion, semantic/lexical indexes, checkpoints, gateway file
|
|
36
|
+
delivery, cron command admission, and symlink aliases. Headless, gateway, sub-agent, cron, and `full-auto`
|
|
37
|
+
execution cannot approve those built-in paths past the check. `HARA_ALLOW_SENSITIVE_FILES=1` is an explicit
|
|
38
|
+
launch-time exposure switch for one process: it removes the built-in denies and that process's shell
|
|
39
|
+
protected-read preflight/Seatbelt mask.
|
|
40
|
+
- **Shell guardrails differ by platform.** With the protected-file policy enabled, shell admission statically
|
|
41
|
+
rejects literal protected paths and environment-dump commands on every OS. On macOS, Hara additionally
|
|
42
|
+
applies a Seatbelt read mask to existing
|
|
43
|
+
protected files/directories even when the general write sandbox is off. Linux and Windows have no equivalent
|
|
44
|
+
kernel-enforced read mask: their arbitrary shell code is outside the protected-file boundary, and static
|
|
45
|
+
preflight can be bypassed by indirection or generated code.
|
|
46
|
+
- **Subprocess credentials.** Model-controlled Bash/background jobs, hooks, external agents, and MCP servers
|
|
47
|
+
inherit an environment with secret-shaped and code-injection variables removed. MCP `env` entries are an
|
|
48
|
+
explicit per-server grant; other commands can receive named variables only when the user launches Hara with
|
|
49
|
+
`HARA_SUBPROCESS_ENV_ALLOW=NAME,OTHER`. Tool output is pattern- and exact-value-redacted. Hara's own provider
|
|
50
|
+
process retains its keys.
|
|
51
|
+
- **Secrets at rest.** `~/.hara/config.json` (API keys) and `~/.hara/qwen-oauth.json` (tokens) are written
|
|
52
|
+
`0600`. The optional semantic index skips secret-named files and filters old indexes at query time, so keys
|
|
53
|
+
aren't embedded or sent to an embedding provider. The memory guard screens secret-shaped strings out of
|
|
54
|
+
what the agent saves.
|
|
55
|
+
- **Repository config is untrusted by default.** A project `.hara/config.json` can set only `model`, `theme`,
|
|
56
|
+
`vimMode`, `autoCompact`, and `reasoningEffort`. Endpoint/credential routing, hooks/MCP commands, approval,
|
|
57
|
+
sandbox, guardian, computer control, and all other keys remain global unless the user launches Hara with
|
|
58
|
+
`HARA_TRUST_PROJECT_CONFIG=1` after reviewing that repository. Warnings name ignored/enabled keys but never
|
|
59
|
+
their values. Project config reads reject a symlink `.hara`, final symlinks, hard links, oversized files,
|
|
60
|
+
and files/directories that change identity during the read.
|
|
61
|
+
- **Identity pins are bound, not followed.** `.hara-profile` reads reject symlink/hard-link aliases and
|
|
62
|
+
oversized or changing files. Writes use a canonical-parent, no-follow snapshot plus atomic compare-and-swap;
|
|
63
|
+
invalid pin warnings never include the pin's raw content or untrusted path. Git-tracked pins are ignored by
|
|
64
|
+
default so a cloned repository cannot silently switch to an existing personal/org identity; untracked local
|
|
65
|
+
pins remain usable, and the reviewed-repository `HARA_TRUST_PROJECT_CONFIG=1` launch opt-in enables tracked pins.
|
|
66
|
+
- **MCP/external agents are trusted extensions.** They execute outside Hara's protected-file boundary. Every
|
|
67
|
+
interactive tool call requires confirmation, including in `full-auto`; non-interactive runs disable them by
|
|
68
|
+
default. Reviewed automation can explicitly enable them before launch with
|
|
69
|
+
`HARA_ALLOW_TRUSTED_EXTENSIONS=1`. Their inherited environment is still scrubbed, but the extension may use
|
|
70
|
+
its own credentials or access anything its host process permits.
|
|
35
71
|
- **Plugins are code you trust.** Installing a plugin (`hara plugin add`) grants its author code execution:
|
|
36
72
|
its MCP servers and hooks run shell commands on launch. `hara plugin add` **prints the exact commands** a
|
|
37
73
|
plugin will run so you can review them; disable with `hara plugin disable <name>`.
|
|
@@ -39,13 +75,16 @@ local user (who already has your shell).
|
|
|
39
75
|
|
|
40
76
|
## What is *not* a security boundary
|
|
41
77
|
|
|
42
|
-
- **The sandbox confines file writes only** — not reads,
|
|
43
|
-
stays writable.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
78
|
+
- **The general sandbox confines file writes only** — not arbitrary reads, network, or process exec;
|
|
79
|
+
`/private/tmp` stays writable. The protected-file policy is a narrow boundary for Hara's built-in paths,
|
|
80
|
+
plus an OS-enforced shell read mask on macOS only; it is not a complete hostile-code jail. On Linux and
|
|
81
|
+
Windows, treat any allowed network-capable shell as able to read and send anything the Hara process account
|
|
82
|
+
can access. On macOS, the protected-path mask still does not confine ordinary files, network, or process exec.
|
|
83
|
+
- **`@file` mentions** can read ordinary files *you* name (including outside the project), but protected
|
|
84
|
+
files are refused unless you made the launch-time opt-in. Mentions are expanded on user input only.
|
|
47
85
|
- **`full-auto` / `-y`** removes the human gate by your explicit choice. Use it on code and in directories
|
|
48
|
-
you trust.
|
|
86
|
+
you trust. It does not remove built-in protected-path checks or subprocess environment scrubbing, but it
|
|
87
|
+
does not turn Linux/Windows shell preflight into a security boundary.
|
|
49
88
|
|
|
50
89
|
## Reporting a vulnerability
|
|
51
90
|
|