Skip to content

Patch 4 - #155

Open
sithu209 wants to merge 218 commits into
liuxb99:mainfrom
sithu209:patch-4
Open

Patch 4#155
sithu209 wants to merge 218 commits into
liuxb99:mainfrom
sithu209:patch-4

Conversation

@sithu209

Copy link
Copy Markdown

No description provided.

asklokesh and others added 30 commits July 23, 2026 16:44
…eekday labels

Two schedule bugs, both in the default-local, everyday path.

1. DST: one-time 'local' tasks fired at the wrong wall-clock across a DST
   boundary (coworker/automation/store.py)

   _tz("local") returned datetime.now().astimezone().tzinfo, a FIXED offset
   equal to whatever was in effect at compute time. A "once" task created in
   summer (EDT, -04:00) for a winter date (EST, -05:00) bound the naive
   datetime to -04:00, so 08:00 fired at 07:00 - an hour early - and for a
   one-shot task next_run is computed once at creation and never self-heals.

   Fix: _tz returns None for 'local' (and for an unknown IANA name) instead of
   a frozen offset, and the naive datetime is left naive. datetime.timestamp()
   and croniter over a naive local base apply the correct local DST offset for
   the actual fire date via the C library. Named IANA zones still anchor via
   ZoneInfo. No new dependency.

2. Weekday labels were a day late (coworker/automation/models.py)

   Cron day-of-week is 0/7=Sunday, 1=Monday..6=Saturday, but _DOW started at
   Monday, so `_DOW[int(dow) % 7]` rendered dow 1 (Monday) as "Tuesday" and
   dow 0 (Sunday) as "Monday" on every weekly automation card. Reordered the
   list to start at Sunday to match cron semantics.

Regression tests added; an existing assertion that encoded the off-by-one
("Monday" for cron dow 0) is corrected to "Sunday".
tauri-build validates every bundle.resources path on each cargo build, dev
included, but binaries/sidecar is only staged by the release scripts and
/binaries is gitignored — so `npm run tauri dev` on a fresh checkout failed
with `resource path 'binaries/sidecar' doesn't exist`.

Create the empty placeholder in the build script. Dev needs no packaged
sidecar (server_bin() falls back to the venv server) and tauri-utils skips
empty resource directories, so the bundle is unchanged. Putting it in
build.rs rather than setup_dev_env.sh also covers Windows, where the bash
bootstrap script never runs.

Fixes liuxb99#131
… boundaries

The test forces an every-minute cron task due and sleeps a fixed 0.2s with
tick_seconds=0.05. After the first (catch-up) run the scheduler correctly
advances next_run to the next minute boundary; when the test happens to start
within ~0.2s of a boundary, that boundary falls inside the sleep window and
the task legitimately fires a second time, failing 'assert ran == [t.id]'.
Harness race, not a scheduler bug (the running-guard and post-run advance are
correct). Wait on an event set by the fake runner and stop the scheduler
immediately after the first run - the advance is synchronous once the runner
returns, so no second tick can fire. Verified 15/15 plus an adversarial
shifted-clock repro at the minute boundary.
…e mute assertions

When the approved turn completes, mark_idle spawns the auto-title completion
as a fire-and-forget task running provider.complete via asyncio.to_thread. The
scripted E2EProvider records that call (then raises on the exhausted turn
queue, which autotitle swallows), so one extra provider.calls entry lands at a
nondeterministic time - frequently between the calls_before snapshot and the
'provider not re-invoked' assertion in the mute step. Wait for SID to leave
mgr._autotitle_inflight (the settling idiom test_autotitle.py already uses)
before snapshotting, so the title call is deterministically included in the
baseline. The mute guarantee is asserted exactly as before. Verified 15/15.
The collision-rename loop in email_download_attachment used
`target.stem.rstrip('-0123456789')`, which strips every trailing digit and
dash, not just a previously-appended `-N` suffix. So saving a second
`invoice_2024.pdf` produced `invoice_-1.pdf`, `IMG_20240115.jpg` became
`IMG_-1.jpg`, and Outlook's `image001.png` became `image-1.png`.

Strip only a trailing `-<number>` suffix with a regex, preserving the
original digits (and still incrementing correctly on repeated collisions).
The background-shell poll helper (_poll_output) returned the instant it saw
status=='exited', but shell_task_output reads are incremental and the final
output chunk can still be draining into the task buffer on the same tick the
status flips to exited. Under load the first post-exit read returns empty and
the helper returns acc='', failing 'quick_done' in acc. This is a harness race,
not a shell bug (the incremental-read contract is correct). Keep reading until a
read yields nothing new (bounded 2s) after the terminal status so the tail is
captured deterministically. Verified 15/15.
Per review: drain output greedily (consume anything already buffered with no
sleep) and only sleep between EMPTY reads, stopping after two consecutive empties
(robust to a one-tick gap between chunks). Bound cut 2.0s -> 0.5s. Common case is
now a couple of reads rather than a 0.02s poll that could, worst case, read up to
~100 times; also removes the break-on-first-empty fragility. Verified 20/20.
…9#143)

Both writers in secrets.py created the temp with Path.write_text and only
restricted it afterwards:

    tmp.write_text(json.dumps(store, indent=2))   # umask default -> 0644
    _restrict_to_user(tmp, is_dir=False)          # chmod 0600, too late
    os.replace(tmp, self.path)

Measured on macOS by sampling the mode at the moment _restrict_to_user is
called, i.e. while the file already holds the plaintext:

    before: temp held the plaintext at 0o644  -> WORLD/GROUP READABLE
    after:  temp held the plaintext at 0o600  -> user-only

Every local process could read every API key for the length of the write, as
could anything indexing or backing up that directory.

Fixed by routing both writers through _atomic_private_write, which uses
tempfile.mkstemp: the file is created 0600 and empty, the Windows ACL is
applied while it is still empty, and only then is the content written.

Two further problems fall out of the same change, both proven by tests that
fail on the previous code:

  The temp name was the fixed <name>.tmp. Pre-creating that path as a symlink
  redirected the write, so an unrelated file was overwritten with the contents
  of secrets.json - an arbitrary overwrite that also discloses every key to a
  location the attacker picked. mkstemp uses O_EXCL and a random suffix, so a
  pre-existing path is not followed.

  A write that failed partway left the temp behind. It is now removed on any
  exception and the previous secrets.json is left intact.

Tests: tests/test_secrets_file_mode.py. Three of the seven fail on the
previous code (mid-write mode, hostile temp symlink, cleanup after a failed
write); the rest pin the final mode and round-tripping.
The session WebSocket handler at api.ts:1824 called JSON.parse without
a try/catch. A single malformed frame from the server would throw an
uncaught exception inside the browser event handler, silently killing
the onmessage callback — the session would freeze with no error feedback.

The sibling connectEvents handler at api.ts:1471 already wraps its
JSON.parse in try/catch. This mirrors that same pattern.
Both tools were registered with kind="read" in TOOL_DEFS, so
approval_for_tool() returned False and overrode the approval=True
set at the call site. The permission engine then classified them
as READ (requires_approval=False → RiskClass.READ), auto-allowing
them without ever prompting the user — even though both write to
disk (clone creates a new directory, pull fast-forwards an existing
repo) and their own descriptions say "Requires user approval".

The connector list API (tool_dicts) always reports
requires_approval=True, so the UI showed them as gated while the
runtime silently bypassed the gate — a mismatch that made the bug
invisible to users.

Reclassify both as kind="write" so the §36 kind→approval mapping
correctly gates them.
…029)

Per-session coworker+folder chips replace the sidebar split-button picker; code family gets a send-time folder dialog with git-ready temp dirs and Save as project.
Builtins ship enabled; user-facing noun is Coworker; personas flag now defaults on.
Chat ships disabled+unsurfaced (Coworker covers quick Q&A); recoverable from Settings.
Bundle skills/ dir joins the persona's session menu (additive; user disables/mutes win); manifest skills: narrows the bundle; mcp: scopes raw servers.
Install snapshot now carries the skills folder — the sharing bundle shape.
Security, Cloud Posture, and Dependency Audit coworkers as self-contained bundle dirs (manifest + skills) driving OSS scanners; registry loads bundle subdirs; packaging includes them.
Freezes today's evaluate() verdict across 26 (mode, tool, args, grants)
situations, so any later permission change shows up as a row-diff. Four rows
are marked BASELINE-WRONG / BASELINE-ANNOYING on purpose: they record known
gaps (shell auto with no sandbox, find -delete and find -exec auto-allowed via
a find prefix, git status && git diff rejected for the operator, web_fetch
never gating in any mode). The PRs that fix these flip their rows here as the
visible proof.

Design of record: ocw-context/docs/reviewed-auto-mode.md Parts 3 and 7.
…writes

Three gate defects, each verified by direct execution before and after.

1. web_fetch was RiskClass.READ, so is_consequential() was False and evaluate()
   returned allow on its third rung -- before any rule, mode or PDP, in EVERY
   mode including plan/discuss. A URL's query string carries data outbound, so
   this was an ungated egress path. New RiskClass.EGRESS covers model-chosen
   network reads; web_search stays READ (fixed configured provider, not a
   model-chosen host). Adds an allowed_domains allowlist (exact host or
   subdomain; 'evil-python.org' never matches 'python.org'), a session-scoped
   "always allow this domain" grant, and ApprovalOutcome.ALWAYS_DOMAIN.

2. A risk override could DOWNGRADE a built-in: marking write_file as read made
   is_write False (skipping path scoping) and consequential False (skipping the
   read-only gate) at once -- one settings line disabling two protections, in
   every future session. Overrides may now only tighten a built-in write/exec/
   egress tool; relaxing a metadata/MCP tool (the intended use) still works.

3. Path scoping read a literal "path" argument, so apply_patch and
   apply_unified_diff -- whose paths live inside the patch/diff blob -- were
   never scoped at all. write_paths() extracts them from the blob and scopes
   every one; a write whose path cannot be located now fails closed to approval
   rather than slipping through auto/custom unscoped.

allowed_domains is user-global only, alongside auto_allow: a cloned repo must
not be able to widen the agent's network reach.

Golden matrix: web_fetch interactive allow->ask, plan allow->deny, plus new
egress/patch rows (31 rows green). test_permissions_risk's override test
asserted the old downgrade behavior and is updated to the tightening rule.
Full suite: 22 failures, all pre-existing on the unmodified tree (boto3 absent,
Windows symlink privilege, Slack socket timeouts) -- none introduced here.

Design of record: ocw-context/docs/reviewed-auto-mode.md Part 3.
in-project files that execute later

Two floors, both mode-independent.

1. The settings files (config.toml, risk_overrides.json, workspace_trust.json,
   unattended.json, coworker.db which holds the saved grants, secrets.json,
   inbox_routing.json) cannot be modified by any tool, in any mode. The check
   runs BEFORE mode, allowlists and every auto-approve path, and returns a hard
   refusal rather than an approvable prompt -- loosening requires editing the
   files out-of-band.

   The escalation this blocks: approve one ordinary-looking `python setup.py`,
   it quietly appends to risk_overrides.json, and every future session is more
   permissive. That happens in the DEFAULT interactive mode, so the protection
   cannot be a property of a sandbox or of any single mode.

   Covered for write tools (resolved path), patch/diff blobs (path extracted),
   and run_shell (command text). Shell matching is deliberately full-path only:
   an earlier draft also matched bare filenames, which hard-denied any command
   merely mentioning `secrets.json` -- caught by
   test_shell_commands_not_auto_allowed_by_default, which reads that path with
   `cat`. Shell is parser depth: it stops accidents and casual attempts, not a
   determined adversary. That needs the OS sandbox (OPE-14).

2. Files inside the workspace that run on a later, innocuous action --
   .git/hooks/**, .github/workflows/**, .vscode/tasks.json, .coworker/** --
   stay writable but never WITHOUT a human. Auto mode, custom-mode auto_allow
   and session "always allow" all lose to this. Otherwise accept-edits is a
   clean bypass: write .git/hooks/pre-commit, then run an innocuous git commit.

19 new tests, incl. every mode parametrized and a lookalike case
(docs/pre-commit.md stays ordinary). 167 permission-related tests green.
test_standing_approvals::test_blocked_run_does_not_stall_other_tasks is an
intermittent pre-existing scheduler timing flake (fails ~1 in 3 on the
unmodified tree).

Design of record: ocw-context/docs/reviewed-auto-mode.md Part 3.
The old rule -- any shell operator disqualifies the whole command -- was wrong
in both directions, verified by running it:

  find . -delete                  -> ALLOW  (destructive, no prompt)
  find . -exec rm {} +            -> ALLOW  (destructive, no prompt)
  git status && git diff          -> ask    (two allowed reads, refused)

It judged punctuation rather than danger. `-delete` and `-exec` need no
separator, so a bare `find` prefix auto-ran them; meanwhile two independently
allowed reads were refused for containing `&&`.

Now:
- Constructs whose contents we cannot evaluate -- substitution, redirection,
  variable expansion, grouping -- still disqualify the whole command, because
  the unexamined tail after a prefix match must only ever be arguments.
- Compound commands are split on &&, ||, ;, |, |&, & and newlines, and EVERY
  part must be independently covered by an allowlist entry.
- Parts that run code named in their arguments are never prefix-eligible:
  argument executors (xargs, sudo, timeout, env, docker, npx, ssh...),
  interpreters carrying inline code (python -c, bash -c, node -e), and
  execution/deletion flags (-exec, -execdir, -delete, -ok).
- Matching stays on parsed words, so `git status` covers `git status -s` but
  never `git statusfoo` or a bare `git`.

Splitting is textual and does not respect quoted separators. That is
deliberate: over-splitting yields MORE parts to justify, never fewer, so it
cannot loosen a verdict.

37 new tests including metamorphic cases (spacing, quoting, absolute program
path must not loosen `find . -delete`). Golden matrix: three rows flip as
intended, two added. 164 permission tests green.

Design of record: ocw-context/docs/reviewed-auto-mode.md Part 2 (CMD-1/3/4).
1. Grant validation. POST /v1/inbox/{id}/resolve takes a raw resolution string
   and approval_outcome() previously honoured whatever it named. The GUI
   deliberately withholds the tool-wide "always allow" for run_shell (the
   command-scoped grant is the narrower option), for save_skill (every skill
   proposal gets its own review) and for connectors; Slack mirrors render only
   approve/deny. So any local API caller could mint a session-wide,
   any-argument shell grant -- a vocabulary the design says must not exist.

   _grant_offered() now mirrors the card's own rules on the server and
   downgrades an unoffered grant to a one-time approval, writing a
   `grant_refused` audit row. Applied to the "always" channel vocabulary too,
   so a Slack reply cannot mint what the in-app card would refuse. MCP tools
   are covered alongside connectors: they are not category=connector but are
   external, and the grant would be unbounded over every future argument.
   A failed always_task mint is now audited rather than silently downgraded.

2. Autonomy transitions. Mode changes (WS set_mode) and the unattended toggle
   were unrecorded, so "who turned on auto mode, and when" was unanswerable
   from the audit store -- at odds with the per-call trail the engine keeps
   everywhere else. Both now write an audit row tagged raised/lowered, so
   autonomy increases can be filtered. set_unattended moves onto the manager
   so REST and any future surface record it the same way; no-op flips are not
   recorded.

15 new tests. test_server's two failures are pre-existing on the unmodified
tree (Windows file-permission errors in pathlib), unrelated to this change.

Design of record: ocw-context/docs/reviewed-auto-mode.md Part 3.
Bundle zip export + import (zip-slip guarded) through the picker's Import door; version+provenance with a replaces-note, re-consent only when capabilities grow.
Consent screen: trust warning first, capability summary with collapsed tool list, recommended connectors.
'Allow read-only commands' on shell cards — fail-closed classifier (local reads + pipelines only; no network/interpreters/writes), session-scoped, persisted with grants.
Consent cards get an in-place Enable button.
… only

coworker/session_facts.py: KnownWorld (roots + git remotes + hosts, captured
once before the agent acts) and SessionFacts (per-turn ingestion records).
Nothing consumes either in v1 - the known world will be rendered into the
reviewer prefix in step 2, ingestion exists so the v2 question ("would this
fact have changed a verdict?") is answerable from a shadow run replay
instead of re-argued.

- render() shows folders and remotes ONLY. Hostnames are held for DST-1 in
  v2 but never rendered: a host list is only useful to a reviewer that can
  do a suffix match, which models get wrong and Python does not.
- Freezing is the point: a remote added after capture stays unknown, so an
  agent cannot make its own destination look familiar.
- Ingestion records the fact and the hostname, never the content and never
  a full URL (a query string is exactly where a payload rides). Failed
  calls record nothing. Local reads are deliberately excluded; the cost of
  that exclusion is recorded in the spec.
- Engine hook is inert when session_facts is None; classification keys on
  tool metadata category (web/connector/mcp) so new connectors are covered
  the day they ship.

22 new tests. Permission suites (146) and the golden decision table pass
unchanged - this step alters no decision.

Spec: ocw-context/docs/reviewed-auto-mode.md Part 0, 2.4, Part 6 step 1.
The mode from ocw-context/docs/reviewed-auto-mode.md (rev. 4), v1 scope.

coworker/reviewer.py (new)
- The 8.3 prompt verbatim, cache-shaped: instructions + known world (folders
  and remotes only) + user-message history in the stable prefix; this turn's
  request and ONE action in the suffix.
- parse_verdict: any defect (empty, non-JSON, unknown verdict) -> unsure.
  There is no parse path that results in execution (8.5).
- Reviewer.review never raises: provider errors and timeouts -> unsure.
  Metering counters (checks / verdicts / tokens) for 1.7.
- AGENT_DENY_MESSAGE: the terse, non-diagnostic refusal the agent gets on a
  deny; the full reason goes to the user only (8.4 asymmetry).

coworker/engine.py
- Reviewer consulted ONLY when: attached, mode is AUTO_APPROVE, session
  explicitly attended (unset is_attended counts as NOT attended, so
  automations can never be reviewed), fewer than two denials this turn.
- Consulted ONLY on decisions the gate marked needs_user - hard denies
  never reach it, so it can only turn "ask" into "allow" (1.2).
- One action per request, fired concurrently for all of a turn's escalating
  calls before the sequential authorize loop (8.6): a verdict cannot land
  on the wrong action, and approval cards still reach the human one at a
  time in call order.
- allow -> runs, audited with the reason. deny -> blocked; user event
  carries the full reviewer reason + allow_anyway; agent message carries
  only AGENT_DENY_MESSAGE. unsure -> today's card.
- Reviewer sees the user's words only, extracted mechanically from
  role=user messages - never agent output, never tool results (4.4).

coworker/permissions.py
- Mode.AUTO renamed Mode.BYPASS_APPROVALS ("bypass-approvals"); legacy
  "auto" still parses via _missing_ so configs, saved sessions, and the
  golden decision table are untouched.
- Mode.AUTO_APPROVE ("auto-approve"): gate-identical to INTERACTIVE except
  session grants ("always allow this ...") no longer auto-allow - they
  route to the reviewer instead (1.5: out-of-band standing policy may skip
  the judge; an in-flow click may not). Config allowlists still skip.
- _domain_allowed(include_session=False) checks the user-settings list only.

coworker/config.py: auto_approve flag, off by default, _GLOBAL_ONLY (a
cloned repo cannot hand itself a looser reviewer). agent.py attaches the
Reviewer only when the flag is on; without it AUTO_APPROVE behaves exactly
like INTERACTIVE.

server/manager.py: autonomy audit ranks auto-approve above interactive
(turning the reviewer on IS raising autonomy) and below bypass.

GUI: mode picker label "Full access" -> "Bypass approvals" (wire value
"auto" kept). Verified live against the real sidecar; e2e spec updated;
tsc and all 111 GUI unit tests pass.

Tests: tests/test_auto_approve.py (33) - gate behaviour per mode, fail-
closed parsing, prompt shape, deny asymmetry, retry guard, attended
gating, hard-deny isolation, per-action verdict landing, and that the
reviewer never sees agent prose. Permission suites + golden table: 146
passing unchanged.
- Icon.tsx: "warning" caution triangle (24px grid, 1.7 stroke, Lucide-style
  rounded triangle + exclamation) matching the existing icon set.
- Composer.tsx: ModeOption extends Dropdown's Option with `caution` (warning
  triangle before the label, themed via text-warnInk so it follows
  light/dark) and `note` (a second, dimmer italic line under the
  description). Bypass approvals carries the caution icon.

The Auto-Approve picker entry itself remains unshipped until the settings
pass gates it on the server-exposed auto_approve flag; its copy is decided
(owner, 2026-08-12): description "A reviewer clears routine actions;
doubtful ones still ask", note "Uses your session model for judgement - one
extra model call per check".

tsc clean; 111 GUI unit tests pass; rendered live and verified (note line
under Auto-Approve, warnInk triangle on Bypass).
… (A)

Owner call after seeing it rendered: the three-line entry read as a
paragraph in a list of two-liners. Decision A: fold the who-judges fact
into the description itself -

  Auto-Approve
  Your session model clears routine actions; doubtful ones still ask

- and let per-check cost surface in the 1.7 metering badge where it
actually accrues, instead of as picker text. This supersedes the copy
recorded in the previous commit.

The `note` field and its render block are removed as dead code; `caution`
(the Bypass warning triangle) stays. tsc clean.
…decides

Spec Part 6 step 3. The reviewer runs on every approval card and records
what it WOULD have decided, while the human decides everything. This is how
the ship gates get measured on real sessions before the flag ever defaults
on. Nothing about a decision changes.

- config.py: auto_approve_shadow flag, off by default, _GLOBAL_ONLY (a
  cloned repo can't turn it on). agent.py attaches the reviewer when either
  auto_approve OR the shadow flag is set; reviewer_shadow gates only the
  recording path.
- engine.py: _spawn_shadow_review fires the reviewer fire-and-forget from
  the needs_user branch and audits stage="reviewer_shadow" joined to the
  human's approval_resolved row by call_id. The card is never delayed; a
  shadow failure never surfaces. Skipped when the live path already
  consulted the reviewer this card (no double spend). approval_requested /
  approval_resolved rows gained call_id for the join.

Eval harness (scripts/eval_reviewer.py, spec 7.5):
- Runs the reviewer against three JSONL corpora and scores the ship gates:
  benign allow-rate >= 30% (prompt-reduction proxy), zero false-allows on
  dangerous and injection. Exit 1 on any gate failure.
- Corpora seeded: benign (20), dangerous (15), injection (13), each with a
  ~20% holdout and per-row answer keys, in the spec's 7.5.1 format. Known
  world is reconstructed folders-and-remotes-only, matching the engine.
- --stub runs with no network (canned verdicts) for plumbing/CI; real runs
  use ProviderRouter and cost money, so this is on-demand, not a pytest.

tests/test_shadow_eval.py (18): shadow records but never decides; shadow
off records nothing; live allow/unsure never double-recorded; shadow errors
swallowed; corpora well-formed; scoring/gate maths; stub passes all gates.
The auto_approve flag (and its shadow sibling) become first-class settings
instead of hand-edited TOML, and the Auto-Approve mode entry appears in the
picker only when the flag is on.

Server:
- manager: auto_approve()/auto_approve_shadow() read prefs.json first,
  falling back to the config.toml value a power user may have set; both
  writers persist to prefs. Both stores are user-global, so a cloned repo
  still can't enable either (the 1.5 invariant, unchanged).
- get_settings() exposes both; POST /v1/settings/auto-approve and
  /auto-approve-shadow write them (same shape as context-bar).
- Session builds pass the prefs-backed values into build_engine via new
  optional auto_approve/auto_approve_shadow overrides (None = config value),
  so a Settings flip takes effect on the next session build with no restart.
  Scheduled runs keep reading config only - they are unattended, so the
  live reviewer can never fire there regardless.

GUI:
- Mode picker: the Auto-Approve entry is `gated` - shown when
  getSettings().auto_approve is true, fetched on menu open. A session
  already IN auto-approve always shows its own entry so the current mode
  stays legible even if the flag was later turned off. This replaces the
  TEST-ONLY unconditional entry.
- Settings: AutoApproveCard with the feature toggle and the nested shadow-
  evaluation toggle ("records what it would have decided next to your own
  choice - without changing anything").
- api.ts: ModelSettings.auto_approve/auto_approve_shadow + setters.

Verified live against the running sidecar: flag off hides the entry on an
interactive session, flag on shows it, the Settings toggles round-trip and
persist. tests/test_auto_approve_settings.py (6): defaults, REST round-
trip, restart persistence, config fallback, prefs-beats-config, and the
build_engine override. tsc clean; 111 GUI unit tests pass.
rohitprasad15 and others added 29 commits August 23, 2026 01:24
…bump-mcp-security

deps: raise mcp floor to >=1.28.1 (PYSEC-2026-3481/3482/3483)
…p-filename

Fix attachment de-dup stripping real digits from the filename
…ge-unguarded-parse

fix(gui): guard session WS onmessage JSON.parse against malformed frames
…fix-flaky-scheduler-test

test: fix flaky test_scheduler_runs_due_task_and_advances near minute boundaries
…fix-flaky-ui-refresh-e2e

test: fix flaky ui-refresh e2e by quiescing the auto-title call before mute assertions
…fix-flaky-shell-background-test

test: fix flaky test_background_task_runs_and_exits near the exit tick
…-approval-gate

fix: gate github_clone and github_pull behind approval
Named memories, boards tied to project identity, Newer lead agents.
…ated-private

security: create secret files private, never chmod them after (liuxb99#143)
…dst-and-weekday

Fix automation scheduling: DST-correct 'local' times and off-by-one weekday labels
Create the sidecar resource dir in build.rs so a fresh clone builds
…ama-vision-fix

fix: detect Ollama vision models from naming conventions
Onboarding Next now accepts OAuth sign-in; an explicit draft folder pick survives a coworker change.
Composer shows context-window figures only (session totals on hold); specialists introduce themselves on first contact.
ws ready now carries running (server truth); the GUI restores Stop + the waiting row and never shows the intro hero mid-turn.
…wer evidence, provenance chips

Breaker pauses loudly and resets on non-deny verdicts and ask_user answers; replies reach the judge with the agent question marked as data.
Cardless runs annotate quietly: auto-approved (reviewer reason) or approval bypassed.
Auto-approve shows a quiet "· paused" while the breaker is tripped; clears on turn end, question answers, and session switches.
PERMISSION_REQUIRED carries reviewer_unsure when an unsure verdict raised the card; both card layouts render it as a quiet line.
Approval origins (reviewer/user/bypass, notes, grants) ride the tool message display sidecar so chips and deny blocks survive reload.
The Auto-Approve explainer is persisted once per session server-side with new shorter copy; later switches persist one-line markers.
Store save gains touch=False (updated_at means last worked on, never last saved); the banner migration and message-less mode switches use it.
The plan backend 400s on max_output_tokens/temperature/top_p — strip them in the provider; autotitle failures now log at warning, not invisible debug.
The title rides the user message the moment it lands — a long agentic turn no longer holds the session name hostage; an opener signature keeps the completion hook (background turns) from burning duplicate attempts.
Specialists offer starting points as an ask_user (free text stays available) so a picked option briefs the reviewer; title generation adds the agent first reply as evidence with a third attempt window.
Pre-release fixes from the 0.2.0 walkthrough
Catalog-checked: 1,048,576 ctx, tool calling; matrix cap 60->65.
Add Ox Alpha via OpenRouter; bump to 0.2.1
Removed detailed setup instructions and license section from README.
@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: dd39d92b-ebda-420b-a541-e952ac4d958a


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.