Commit Graph
748 Commits
Author SHA1 Message Date
github-actions[bot] cf29ef710e chore: update clone traffic data [skip ci] 2026-05-29 07:23:59 +00:00
Jon Saad-FalconandGitHub 3aa24b2709 Merge pull request #429 from open-jarvis/feat/opencode-agent
feat(agents): add OpenCodeAgent — run opencode on a local engine
2026-05-28 20:38:46 -07:00
krypticmouseandClaude Opus 4.7 c6f172cbdc docs(agents): add eval-backed model-capability guidance for OpenCodeAgent
A 27B local model (Qwen3.5-27B via vLLM) passed a 7-task coding suite cleanly
(create/edit/bug-fix/implement-to-pass-tests/multi-file, verified by running
code + pytest); an 8B model was unreliable. Document so users pick a capable
model for real coding work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 02:59:35 +00:00
krypticmouseandClaude Opus 4.7 00b85b71dd fix(agents): unwrap wrapped engines to derive opencode provider URL (+ clear guard)
The real `jarvis ask --agent opencode` path passes an InstrumentedEngine
(telemetry wrapper) whose underlying engine — and its `_host` — lives at
`_inner`. The base-URL derivation only checked the top object, so it returned
"", no provider was registered, and opencode 500'd on `openjarvis/<model>`.
Direct construction with a raw engine masked this; only the CLI path exposed
it.

- _derive_openai_base_url now unwraps up to 6 wrapper layers
  (`_inner`/`_engine`/`_wrapped`) to find `_host`/`base_url`.
- run() resolves the provider/model spec up front and, when it genuinely
  can't (no base URL + bare model name), returns a clear actionable error
  instead of letting opencode 500.

Tests: wrapper-unwrap derivation + unresolvable-provider guard. 20 passed,
ruff clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 01:10:25 +00:00
krypticmouseandClaude Opus 4.7 6a011b4abb fix(agents): deterministic opencode permissions + no workspace pollution
Two hardening fixes for headless use, found while verifying real runs:

- Permissions: opencode's interactive default *asks* before some actions (and
  `plan` asks before bash), which would block forever with no TTY. The agent
  now writes an explicit permission policy: `build` allows edit+bash, `plan`
  denies them (read-only), overridable via a `permission` kwarg. Verified: a
  bash task completes without hanging and plan mode refuses to create files.
- Config no longer written into the user's workspace. We now write provider +
  permission config to a private temp file referenced via `OPENCODE_CONFIG`
  (confirmed honored by opencode), keeping the workspace clean while opencode
  still operates there as cwd.

Tests updated to cover `_build_config` (provider presence, per-mode
permission, custom override, no-pollution). 18 passed, ruff clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 01:07:00 +00:00
krypticmouseandClaude Opus 4.7 20f90f3ca0 fix(agents): recover opencode tool-results from the full turn, not just the final message
A real-model E2E (Ollama qwen3:8b) exposed what unit tests with synthetic
parts missed: `POST /session/{id}/message` returns only the final assistant
message (text/reasoning), while ToolParts live in intermediate assistant
messages. The parser was reading the wrong message, so tool_results was always
empty even when opencode actually edited files.

- run(): after the prompt POST, GET /session/{id}/message and collect parts
  across the whole turn for tool extraction (content still comes from the
  final message). Verified against a live opencode session.
- _extract_tool_results: success now keys on opencode's state.status ==
  "completed" (states: completed | error | running | pending).
- Test now feeds the real full-turn message shape and asserts the write tool
  is recovered.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 00:56:36 +00:00
krypticmouseandClaude Opus 4.7 4fa9163ea9 feat(agents): add OpenCodeAgent — run the opencode coding agent on a local engine
Adds an `OpenCodeAgent` (registry key `opencode`) that delegates coding tasks
to opencode (https://opencode.ai, MIT) while keeping inference local-first:
OpenJarvis's engine backs opencode via an OpenAI-compatible provider.

How it works:
- Derives an OpenAI-compatible base URL from the engine (e.g. Ollama/vLLM at
  `<host>/v1`) and writes an `opencode.json` registering it as an
  `@ai-sdk/openai-compatible` provider (`openjarvis/<model>`).
- Spawns a headless `opencode serve` (loopback, random port), waits for
  `/global/health`, then drives a session: `POST /session` →
  `POST /session/{id}/message` with `model={providerID,modelID}` + agent
  (`build`/`plan`) → parses message `parts` (text → content, tool → tool_results)
  into an `AgentResult`. `close()` disposes the server.
- opencode is an external binary (not bundled); `run()` returns a clear,
  actionable error when it's missing, mirroring ClaudeCodeAgent's degradation.

Verified end-to-end against the real opencode binary wired to a stub
OpenAI-compatible engine: opencode called the local endpoint and the agent
parsed the response (content/finish/model) correctly. Unit tests cover part
parsing, base-URL derivation, provider-config writing (incl. merge), binary
detection, graceful degradation, and run() parsing with a mocked client — 15
passed, ruff clean. Registered via the standard try/except import in
agents/__init__.py; documented in docs/user-guide/agents.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 00:41:22 +00:00
Robby ManihaniandGitHub 23ed17fe12 Refine CLI branding: readable wordmark, new tagline, research footer (#424) 2026-05-28 12:07:50 -07:00
Robby ManihaniandGitHub 26285e56fa fix(agents): wire continuous-agent Interact tab end-to-end + CLI workflow polish (#425) 2026-05-28 12:07:03 -07:00
Andrew ParkandGitHub c6448f7cf2 fix(desktop): preselect model in onboarding so first chat doesn't 400 (#427) 2026-05-28 11:19:52 -07:00
Jon Saad-FalconandGitHub 6a27094658 Update README.md 2026-05-28 10:30:12 -07:00
github-actions[bot] c14c7c24c0 chore: update clone traffic data [skip ci] 2026-05-28 07:24:03 +00:00
Jon Saad-FalconandGitHub 75d26d23ea Merge pull request #422 from open-jarvis/fix/persona-files-persistent-agents
fix(agents): persistent agents honor SOUL.md / MEMORY.md / USER.md persona files (#376)
2026-05-27 10:57:12 -07:00
krypticmouseandClaude Opus 4.7 4ece9a933e fix(agents): persistent agents honor SOUL.md / MEMORY.md / USER.md persona files (#376)
SystemPromptBuilder (which loads the SOUL/MEMORY/USER persona files) was wired
only into the one-shot `jarvis ask` path, so persistent agents run through
AgentExecutor ignored persona entirely. The naive "pass prompt_builder" fix is
insufficient: `prompt_builder` was dropped at every __init__ hop
(ToolUsingAgent never accepted/forwarded it), and monitor_operative/operative
assemble their own system prompt and never consult `_prompt_builder` — so they
would silently ignore it even if it arrived.

Fix:
- `SystemPromptBuilder.persona_sections()` returns just the SOUL/MEMORY/USER
  sections (no agent template), for agents that build their own prompt and want
  to *append* persona rather than have it replace their instructions.
- `BaseAgent._apply_persona()` appends persona to a self-assembled prompt
  (no-op without a builder or persona files).
- Thread `prompt_builder` through the __init__ chain: ToolUsingAgent now
  accepts and forwards it to BaseAgent; monitor_operative and operative forward
  it and call `_apply_persona()` on their assembled system prompt.
- AgentExecutor constructs a SystemPromptBuilder from config and passes it to
  any agent whose __init__ accepts it (same gating as session_store /
  memory_backend). Agents that override __init__ without forwarding (e.g.
  orchestrator) opt out automatically and keep their own machinery.

Specialized prompts are preserved — persona is appended, not substituted. The
one-shot path is unchanged.

Verified: persona_sections() excludes the template but build() still includes
both; monitor_operative/operative receive the builder through the chain and
their assembled prompt includes the SOUL content. New tests in
tests/agents/test_persona_persistent.py (11 passed; ruff clean).

Closes #376

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 17:21:43 +00:00
Jon Saad-FalconandGitHub 00065cd960 Merge pull request #418 from open-jarvis/fix/managed-agent-streaming-parity
fix(server): managed-agent streaming parity — tool_calls replay, sampler params, tool DI (#382, #386, #395)
2026-05-27 10:16:17 -07:00
Tanvir BhathalandGitHub 0702f2793c (bug): telemetry fixes (#421) 2026-05-27 09:36:26 -07:00
github-actions[bot] f6156f480b chore: update clone traffic data [skip ci] 2026-05-27 07:30:01 +00:00
github-actions[bot] eb08987dae chore: update clone traffic data [skip ci] 2026-05-26 07:15:55 +00:00
krypticmouseandClaude Opus 4.7 5acc86d7cc fix(server): managed-agent streaming parity — tool_calls replay, sampler params, tool DI (#382, #386, #395)
`_stream_managed_agent` had diverged from the canonical cli/ask.py path and
lost three behaviours. All three are fixed via small extracted, unit-tested
helpers:

- #382: cross-request history replay dropped stored `tool_calls`, so the model
  never saw its own prior tool use and fabricated tool output on turn 2+.
  `_replay_history_messages` now reconstructs the assistant tool-use message
  plus matching tool-result messages (synthesised, consistent tool_call_ids).
- #386: only temperature/max_tokens reached the engine. `_sampler_kwargs`
  forwards repetition_penalty / top_p / top_k / min_p / frequency_penalty /
  presence_penalty when set in the agent config (opt-in; default agents send
  nothing extra). Fixes degenerate repetition loops on local models with no
  repetition_penalty.
- #395: tools were built with a bare `tool_cls()`, so memory_* / channel_* /
  llm tools loaded with no backend and failed on every call.
  `_instantiate_managed_tool` injects backend / channel / engine the same way
  cli/ask.py::_build_tools does.

Verified empirically: replay emits user → assistant(tool_calls) → tool(result)
with matching ids; sampler extraction forwards only set keys; DI gives memory
tools a backend and llm the engine/model. New tests in
tests/server/test_managed_agent_streaming.py (helpers are pure, so verifiable
without a live engine). 38 passed locally incl. existing route tests.

Closes #382
Closes #386
Closes #395

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 03:22:14 +00:00
Jon Saad-FalconandGitHub f827a8165d Merge pull request #417 from open-jarvis/security/default-deploy-auth
security(deploy): require auth (or loopback) in default deployments (#221)
2026-05-25 19:07:17 -07:00
Jon Saad-FalconandGitHub 0d3cc6db51 Merge pull request #416 from open-jarvis/security/websocket-a2a-auth
security(server): authenticate WebSocket handshakes + A2A requests (#217)
2026-05-25 19:07:05 -07:00
Jon Saad-FalconandGitHub b0f133a42d Merge pull request #415 from open-jarvis/security/template-loader-rce
security(tools): fix RCE in template loader (eval + shell=True) (#216)
2026-05-25 19:06:54 -07:00
krypticmouseandClaude Opus 4.7 9cd760ad1e security(deploy): stop default deployments shipping an open, unauthenticated server (#221)
All three deployment methods bound 0.0.0.0:8000 with no API key, so following
the README produced a server reachable from any device on the network with no
auth. `check_bind_safety` already refuses to start a non-loopback bind without
a key (so these configs actually failed to start) — this wires the key in so
the documented path yields a *working, authenticated* server.

- docker-compose.yml: require `OPENJARVIS_API_KEY` via `${VAR:?...}` so
  `docker compose up` fails fast when unset; added `deploy/docker/.env.example`
  (un-ignored in .gitignore).
- systemd: add `EnvironmentFile=/etc/openjarvis/env` (no `-` prefix, so a
  missing key file blocks startup rather than exposing an open server).
- launchd: bind `127.0.0.1` by default (the personal-device default — no
  network exposure, no key needed) with a documented, commented opt-in to
  0.0.0.0 + `OPENJARVIS_API_KEY`. Avoids shipping a usable default credential.
- Docs (docker/systemd/launchd) updated with the key-setup step.
- Tests assert each config can't reintroduce an open server, plus
  `check_bind_safety` behavior across loopback/public × key/no-key.

Closes #221

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 23:56:55 +00:00
krypticmouseandClaude Opus 4.7 87e978ef20 security(server): authenticate WebSocket handshakes and A2A requests (#217)
`AuthMiddleware` is a BaseHTTPMiddleware and never intercepts WebSocket
upgrade requests, so `/v1/chat/stream` and `/v1/agents/events` accepted any
connection — leaking all agent events/message content and allowing
unauthenticated inference even when an API key was configured for HTTP. The
A2A JSON-RPC server likewise dispatched every request without auth.

- Add `websocket_authorized(websocket, expected_key)` (constant-time compare)
  and check it in both WS handlers BEFORE `accept()`, closing with code 1008
  on failure. Token is read from `?token=` (browsers can't set WS headers) or
  an `Authorization: Bearer` header. `create_app` now exposes the key via
  `app.state.api_key`; when empty, auth is disabled, matching the HTTP
  middleware's local-default behavior (so loopback dev is unchanged).
- A2AServer gains an optional `auth_token`: `handle_request(token=...)`
  rejects with JSON-RPC -32001 before dispatch when configured, advertises
  `{"schemes": ["bearer"]}` on the agent card, and stays open when unset.
  Added `A2AConfig.auth_token`.

Verified empirically against the real mounted endpoints via TestClient: no
token / wrong token are rejected at the handshake (WebSocketDisconnect),
correct token streams normally, and no-key configs still connect freely.

Closes #217

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 23:51:29 +00:00
krypticmouseandClaude Opus 4.7 47ca09f1a3 security(tools): eliminate RCE in template loader eval() and shell=True (#216)
`python`-action tool templates evaluated expressions with `eval()` under a
restricted `__builtins__`. That sandbox is escapable via attribute walks like
`str.__class__.__mro__[-1].__subclasses__()`, reaching `object.__subclasses__()`
and arbitrary code. `shell`-action templates interpolated parameters into a
string and ran it with `shell=True`, so a value like `; rm -rf ~` or
`$(curl evil)` executed in the host shell.

Fixes:
- Replace `eval()` with a small AST interpreter (`safe_eval_expr`) that
  implements an explicit node allowlist — literals, names, arithmetic/boolean/
  comparison ops, ternaries, subscripts, container literals, and calls to a
  fixed set of builtins only. Attribute access, lambdas, comprehensions, and
  dunder names have no implementation and raise `ValueError`, so the escape
  vectors are unreachable by construction. No `eval`/`exec` remains.
- Shell action: tokenize the FIXED template with `shlex.split` first, then
  substitute params into individual argv elements and run with `shell=False`.
  Injected metacharacters become inert literal arguments.

All shipped builtin templates (`str(float(value))`, `str(input) if input
else ...`, etc.) continue to work. Verified empirically: every known escape
payload is rejected and a `; touch <marker>` / `$(touch <marker>)` /
backtick injection never creates the marker file.

Closes #216

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 23:45:59 +00:00
Jon Saad-FalconandGitHub 7e8db280e4 Merge pull request #413 from open-jarvis/ci/desktop-stable-updater-channel
ci(desktop): stable (desktop-latest) + edge (desktop-edge) updater channels
desktop-edge
2026-05-25 16:41:08 -07:00
krypticmouseandClaude Opus 4.7 e3f2b008d2 ci(desktop): split updater into stable (desktop-latest) + edge (desktop-edge) channels
The installed desktop app polls `desktop-latest/latest.json`. Previously
every push to `main` (autotag -> v*.devN -> desktop.yml dispatch) rebuilt
and republished `desktop-latest` as a DEV prerelease, so stable users were
auto-updated onto unvetted dev builds, and any manual stable mirror was
clobbered on the next merge.

Split the streams so the app's channel only ever serves vetted stable:

- Dev/rolling builds (v* autotag + manual workflow_dispatch) now publish to
  a new `desktop-edge` pre-release. The shipped app does not poll edge, so
  dev builds never auto-install onto stable users.
- Stable `desktop-v*` builds publish the user-facing release as before, then
  a new `refresh-stable-channel` job copies that release's signed
  `latest.json` into `desktop-latest` (mirror; URLs already point at the
  desktop-v* assets). Cut a `desktop-v*` tag to ship an update.
- `clean-release` now targets `desktop-edge`; `desktop-latest` is never
  wiped by CI.

No app/tauri.conf.json change — the updater endpoint stays `desktop-latest`.
Doc updated to describe the now-implemented stable/edge split.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 23:36:17 +00:00
Jon Saad-FalconandGitHub cdae426d48 docs: fix broken desktop download links → stable desktop-v1.0.2 release (#412)
Repoints all desktop download links (README, docs/index.md, downloads.md, getting-started/installation.md) from the removed desktop-latest prerelease (with wrong 0.1.0 filenames) to the stable desktop-v1.0.2 release. All 5 URLs verified live (200). macOS .dmg now included (addresses #356).
2026-05-25 16:20:33 -07:00
krypticmouseandClaude Opus 4.7 ae9727599b docs: point desktop download links at the stable desktop-v1.0.2 release
Every desktop download link in the docs was broken on two counts:
1. They pointed at the rolling `desktop-latest` prerelease, which had
   been removed (404 for all of README, docs/index.md,
   docs/downloads.md, docs/getting-started/installation.md).
2. They used the wrong version in the filenames (`OpenJarvis_0.1.0_*`)
   — the actual published assets were never `0.1.0`.

Repointed all four files at the new stable `Desktop desktop-v1.0.2`
release with the exact asset filenames it ships
(`OpenJarvis_1.0.1_*` — the Tauri bundle version is 1.0.1, distinct
from the 1.0.2 Python/CLI release). This release also includes a
macOS universal `.dmg`, which the prior desktop releases lacked
(addresses #356 "No Mac Download") — so the macOS rows now say
"Universal" (Apple Silicon + Intel) instead of "Apple Silicon".

All five download URLs verified live (HTTP 200) against the
desktop-v1.0.2 release before committing.

Note: `docs/desktop-auto-update.md` still references the
`desktop-latest` rolling channel — that's the auto-updater's endpoint,
a separate concern from the manual download links, and is left as-is.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 23:18:33 +00:00
Robby ManihaniandGitHub a86d022947 fix(agents): repair continuous monitor_operative agent (parrot loop, tool calling, traces) (#407) 2026-05-25 11:08:14 -07:00
Robby ManihaniandGitHub 8e6bc343d8 fix(connectors): validate credentials before persisting + populate Gmail URLs (#410) 2026-05-25 11:07:35 -07:00
Jon Saad-FalconandGitHub 56c9a59f8d release: v1.0.2 — fix broken PyPI wheel (#372) + pynvml/Windows/install fixes (#411)
Bumps 1.0.1 → 1.0.2 so the merged fixes (#372 wheel packaging, #389 pynvml, #373 Windows RAM, #331 desktop diagnostics, #337/#352 install URL) can ship to PyPI. See PR #411.
v1.0.2 desktop-v1.0.2
2026-05-25 10:51:56 -07:00
krypticmouseandClaude Opus 4.7 bed3524b62 release: v1.0.2
Patch release bundling the fixes merged since v1.0.1. The headline is
#372 — the v1.0.1 wheel on PyPI is missing `openjarvis/traces/`, so
every `pip install openjarvis==1.0.1` breaks at import. PyPI filenames
are immutable, so the fix has to ship under a new version number.

Bumps version 1.0.1 → 1.0.2 and adds the CHANGELOG entry covering
#372 (wheel packaging), #389 (pynvml warning), #373 (Windows RAM),
#331 (desktop uv-sync diagnostics), and #337/#352 (install URL → GitHub
Pages).

After this merges, cut the release:
  uv build
  unzip -l dist/openjarvis-1.0.2-*.whl | grep traces   # verify
  twine upload dist/openjarvis-1.0.2-*

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 17:49:40 +00:00
github-actions[bot] eb5d1e467f chore: update clone traffic data [skip ci] 2026-05-25 07:37:54 +00:00
Jon Saad-FalconandGitHub b43f4d2291 refactor(desktop): extract testable uv-sync error helpers + unit tests (#331) (#406)
Extracts the #331 uv-sync error-formatting logic into pure functions with 7 unit tests, now run via cargo test in desktop.yml's validate job. Verified: all 7 pass on the real Tauri crate in CI.
2026-05-24 08:31:54 -07:00
krypticmouseandClaude Opus 4.7 658effb964 refactor(desktop): extract testable uv-sync error helpers + unit tests (#331)
The uv-sync failure handling added in #398 was inline in the async
`boot_backend` GUI path, so its logic — exit-code rendering and the
stderr "tail" extraction — could only be verified by running the
desktop app. This extracts the pure logic into three free functions
and adds unit tests, so the message formatting is now covered by
`cargo test` with no GUI / webview runtime needed.

Extracted:
- `uv_sync_stderr_tail(stderr, max_chars)` — last N chars of stderr,
  trimmed, on char boundaries. The original inline version used
  `.rev().take(N).collect().chars().rev().collect()`; the new version
  is `skip(count - N)` which is clearer and equally UTF-8-safe (matters
  because Windows consoles emit non-ASCII cp9xx bytes — a byte slice
  could split a codepoint).
- `format_uv_sync_failure(root, exit_code, stderr)` — the non-zero-exit
  message. Now renders a missing exit code (signal-terminated process)
  as "unknown" instead of a misleading "-1".
- `format_uv_sync_spawn_error(root, uv_bin, err)` — the can't-spawn
  message.

`boot_backend` now calls these instead of formatting inline.

Tests (7, in `#[cfg(test)] mod tests`):
- tail returns whole string when shorter than the limit
- tail keeps the END (the actionable line), not the spinner-noise start
- tail trims surrounding whitespace
- tail never splits a multi-byte codepoint (500×"é", limit 100 → exactly
  100 chars, all "é")
- failure message includes exit code + stderr tail + the actionable
  "run uv sync manually" hint
- missing exit code renders as "exit unknown", never "exit -1"
- spawn-error names the uv binary path and repo root

Verified the logic standalone via `rustc --test` (7/7 pass). In CI they
run via `cargo test` in desktop.yml's `validate` job, which already
builds the Tauri crate with the webkit deps and runs on every PR that
touches `frontend/**` — so this changes the existing `cargo check` step
to `cargo test` (a superset: same build coverage, plus the tests).

This doesn't verify the GUI *behavior* (that still needs a human running
the app, or the windows-latest empirical path) — but the error-message
logic that was previously untestable now has automated coverage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 15:26:07 +00:00
Jon Saad-FalconandGitHub 0c34817ecd ci: add windows-latest job to empirically verify Windows code paths (#405)
Adds a windows-latest CI job that executes the real GlobalMemoryStatusEx RAM path (#373), the #293 stdout reconfigure test, and builds+imports the openjarvis_rust PyO3 extension on Windows. Verified green on a real Windows runner (4m1s, all steps success).
2026-05-24 08:08:49 -07:00
krypticmouseandClaude Opus 4.7 c06633e26f ci: add windows-latest job to empirically verify Windows code paths
The `test` job runs only on ubuntu-latest, so the Windows-specific
branches added for #373 (RAM detection via GlobalMemoryStatusEx) and
#293 (cp9xx → UTF-8 stdout reconfigure) were never *executed* in CI —
only unit-tested with mocks on Linux. `tests/hardware/test_hardware_profiles.py::test_total_ram_gb_windows`
has existed all along but is `skipif(sys.platform != "win32")`, so it
silently skipped on every run.

This adds a `test-windows` job that runs on a real Windows runner
(free for public repos) and:

1. Verifies `_total_ram_gb()` returns > 0 on actual Windows — executes
   the real `ctypes.windll.kernel32.GlobalMemoryStatusEx` path (#373).
   Runs as a pure-Python step BEFORE any Rust build, so a flaky
   toolchain install can't mask the result.
2. Runs `tests/hardware/test_hardware_profiles.py` (the now-unskipped
   Windows RAM test) and `tests/cli/test_cli.py` (the
   `test_windows_reconfigures_stdout_to_utf8` test from #293).
3. Builds + imports the `openjarvis_rust` PyO3 extension on Windows —
   the only CI job that does so. The extension is mandatory at runtime
   (`_rust_bridge.py` hard-errors without it), yet nothing else
   verified it compiles/imports on Windows. desktop.yml builds the
   Tauri app's Rust, not this extension.
4. Smoke-tests `jarvis --version`.

Scoped to the platform-relevant test files (not the full 6700-test
suite) so the job stays fast; the slow part is the Rust build, which
doubles as Windows-extension-build coverage.

All `run:` steps are static commands with no `github.event.*`
interpolation — no workflow-injection surface.

Note: #331 (desktop "did not become healthy" — uv sync error
surfacing) is GUI-triggered Tauri boot logic and isn't covered here;
its only automatable surface is string formatting, and testing it
needs the heavy webview build. Left as a possible follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 15:03:11 +00:00
github-actions[bot] deb0dd509c chore: update clone traffic data [skip ci] 2026-05-24 07:09:11 +00:00
Jon Saad-FalconandGitHub a76319841a fix(install): serve install.sh from GitHub Pages as canonical URL (#402)
Resolves the openjarvis.ai SSL failure (#337, #352) by serving the installer from the project-controlled GitHub Pages site. Adds uv prerequisite docs for the Windows desktop path. See PR #402 for the full breakdown and the openjarvis.ai CNAME migration note.
2026-05-23 12:10:00 -07:00
krypticmouseandClaude Opus 4.7 cf8d3e2cbe fix(install): serve install.sh from GitHub Pages, make it the canonical URL
The documented install command pointed at `https://openjarvis.ai/install.sh`,
but that domain is community-operated (not controlled by this project) and
its TLS config broke — every new user hit `sslv3 alert handshake failure`
(#337, #352). Since we can't fix a domain we don't control, this moves the
installer onto infrastructure we DO control: the project's GitHub Pages
docs site.

Changes:

- **`docs/gen_install_script.py`** (new) + **`mkdocs.yml`**: a `gen-files`
  hook copies `scripts/install/install.sh` verbatim into the built site at
  `install.sh` on every `mkdocs build`. Single source of truth — the script
  stays at `scripts/install/install.sh` (still bundled into the wheel as
  `_install_scripts/`); the published copy can't drift. Verified locally:
  `mkdocs build` emits `site/install.sh` byte-identical to the source.

  New canonical URL: `https://open-jarvis.github.io/OpenJarvis/install.sh`
  — HTTPS always valid (GitHub's cert), fully under project control.

- **`README.md`**: canonical command switched to the github.io URL for
  both the Installation and Quick Start blocks. Also addresses the uv
  discoverability gap — explicitly states the curl installer downloads uv
  for you (no prerequisite), and that the Windows **desktop .exe** expects
  uv to be installed first, with the exact PowerShell command.

- **`docs/getting-started/{install,wsl2,macos,linux}.md`**: canonical URL
  switched to github.io. `install.md` gains an "Install URL" info note
  explaining the github.io URL is canonical and that the older
  `openjarvis.ai` URL is community-operated with intermittent TLS issues.

- **`scripts/install/install.sh`** + **`jarvis-wrapper.sh`**: usage comment,
  the WSL re-run hint (added in #399), and the wrapper's re-install message
  all updated to the github.io URL.

Migration note for maintainers: ask whoever operates `openjarvis.ai` to
CNAME it to `open-jarvis.github.io`. Once they do, `openjarvis.ai/install.sh`
will serve this same GitHub Pages content with a valid GitHub-managed cert,
and the nicer brand URL can become canonical again with zero further code
changes. Until then, the github.io URL works and is under our control.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 19:05:26 +00:00
Jon Saad-FalconandGitHub bced6cc274 fix(install): Windows discoverability + Git Bash early bail + concrete uv install command (#399)
Follow-up to PR #398. Three surface fixes for the Windows install confusion documented in two Discord support threads. See PR #399 for the full breakdown.
2026-05-23 08:54:10 -07:00
krypticmouseandClaude Opus 4.7 612d3e1f88 fix(install): make Windows install path discoverable + bail early on Git Bash
Addresses the second half of the Discord support thread on the
"Jarvis server did not become healthy in time" issue (PR #398 fixed
the diagnostic gap; this fixes discoverability of the right install
path so users don't end up there in the first place).

Three changes, all surface improvements:

1. **`README.md`** — explicit Windows section in the Installation
   block. Previously, the only Windows mention was a footnote
   ("Platforms: ... WSL2 on Windows") that came AFTER the `curl … |
   bash` install command. Users on PowerShell would copy/paste the
   command, get a syntax error, then try to debug bash on Windows.
   Now the README clearly says: bash installer is macOS/Linux only;
   Windows users have two paths (WSL2 with one-time `wsl --install`
   setup, or the desktop .exe from Releases). Both link to the
   relevant docs.

2. **`scripts/install/install.sh`** — early bail when running under
   Git Bash / MSYS2 / Cygwin (MINGW*, MSYS*, CYGWIN* per `uname -s`).
   These environments aren't WSL — `uv` and `git` will install to
   Windows-side paths that OpenJarvis can't reach, Ollama integration
   silently breaks, and the user gets to debug it 3 minutes into a
   doomed install. The bail message points at both the WSL2 setup
   command (`wsl --install -d Ubuntu-24.04`) and the desktop .exe
   download as alternatives.

   Verified the case-match doesn't fire on Linux (`uname -s` →
   `Linux`, matches the wildcard fall-through, not the MINGW patterns).

3. **`frontend/src-tauri/src/lib.rs`** — when `resolve_bin("uv")`
   can't find uv, the per-OS error message now contains the exact
   install command for the user's OS, ready to copy/paste. On Windows
   that's the `irm https://astral.sh/uv/install.ps1 | iex` command
   Marc kept reposting on the Discord support thread (5/12-5/14).
   On macOS/Linux it's the standard `curl | sh` installer.

   The previous generic "Install it from https://astral.sh/uv" left
   users guessing whether to use winget, scoop, pip, or the official
   installer — which is exactly the confusion the Discord thread
   captured.

None of these are root-cause code fixes (Discord users' uv installs
fail for environment-specific reasons we can't diagnose remotely),
but together they remove the three biggest friction sources we saw:
copy-paste install command that can't possibly work, doomed git-bash
installs that fail mysteriously, and missing exact install commands
when uv isn't found.

The Tauri change ships in the desktop binary; the README change is
visible immediately on the repo page; the install.sh change reaches
users via openjarvis.ai (when it's restored) and via the GitHub-raw
fallback from PR #398.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 15:48:13 +00:00
Jon Saad-FalconandGitHub 58f7b753bf fix: PyPI v1.0.2 cluster — wheel packaging + pynvml warning + install fallback + uv-sync diagnostics (#398)
Closes #372 #389 #337 #352 #331. Resolves #373 (already on main, awaiting release). See PR #398 for the full per-issue breakdown.

Credits: @gilbert-barajas (#372), @boeani05 (#389), @kumanday + @filactre (#337/#352), @Hris4oG + @NatanelBranski + @Robjes87 + @EmiDaDuck (#331).
2026-05-23 08:36:44 -07:00
krypticmouseandClaude Opus 4.7 158fc83feb fix(desktop): surface uv sync errors so users aren't stuck waiting for health check
Addresses #331 (multiple Windows users hit "Jarvis server did not
become healthy in time" with no actionable detail).

The boot sequence ran `uv sync` with **both** stdout AND stderr piped
to `/dev/null` and discarded the exit code (`let _ = …`). When
`uv sync` failed for any reason — Windows PATH/permission issues,
network problems, lockfile conflicts, stale `.venv/` — the user saw
nothing useful. The boot proceeded to `uv run jarvis serve` in an
under-provisioned venv, then waited the full 600-second health-check
window before showing a generic "did not start" message with no
hint of what actually went wrong.

Fix: capture stderr, check the exit status, and surface a useful
error to the user **before** the long server-start wait, including:
- The exit code
- The last ~800 chars of `uv sync` stderr (where the diagnostic
  message usually lives)
- A concrete next step (open a terminal and run `uv sync --extra server`
  manually for full output)

Also updated the status detail message to "Installing dependencies
(uv sync — may take 1-2 min on first boot)..." so users on slow
connections don't restart the app thinking it's stuck.

Discord support thread (5/12-5/14) shows the same pattern across
multiple Windows users (@ItsVoyage, @Mystic_irl, @doevud, @Sainthood):
all stuck on "Starting api server" / "did not become healthy in time"
for 4+ minutes, with the actual root cause turning out to be a uv
installation issue that the discarded stderr would have surfaced
immediately. The community workaround (uninstall, install Feb
pre-release, run a magic PowerShell `irm` command for uv) is the
right diagnosis applied without diagnostic output — this commit
makes that diagnostic output visible.

Note: this fix lands in the desktop binary's source (`frontend/src-tauri/src/lib.rs`).
Users running the v1.0.1 desktop binary won't see the improved
error message until the desktop release is re-cut from this branch.
Until then, the workaround documented in this PR's `openjarvis.ai`
fallback section (curl the install.sh from GitHub raw) gets new
users past the install step.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 15:31:17 +00:00
krypticmouseandClaude Opus 4.7 52e830e1a4 docs(install): add GitHub-raw fallback for the openjarvis.ai install URL
Addresses #337 (also reported as #352).

`curl -fsSL https://openjarvis.ai/install.sh | bash` — the documented
one-liner — currently fails with:

    curl: (35) ... sslv3 alert handshake failure

Reproduced from this machine just now; @kumanday and @filactre both
report the same against different OpenSSL and LibreSSL versions. The
underlying SSL issue is on the openjarvis.ai server (cert / TLS
config) and needs an operational fix at the infra layer — not
something a code change in this repo can resolve.

What this commit *can* do is unblock users immediately:

- `README.md` (under "Installation"): callout pointing at issue #337
  and the GitHub-mirror fallback.
- `docs/getting-started/install.md`: same callout as a
  Material-for-MkDocs `!!! warning` admonition.

Both link to the canonical script at
`https://raw.githubusercontent.com/open-jarvis/OpenJarvis/main/scripts/install/install.sh`.
The script is identical content — it's the same `scripts/install/install.sh`
served from GitHub's CDN instead of openjarvis.ai. Once the
installer runs, it pulls everything else (`uv` from astral.sh, the
project source from `github.com/open-jarvis/OpenJarvis.git`, Ollama
from `ollama.com`) — none of which depend on `openjarvis.ai`. So
the rest of install proceeds normally.

When the openjarvis.ai SSL issue is fixed at the server / DNS layer,
both callouts can be removed and the canonical URL becomes the only
documented path again.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 15:25:08 +00:00
krypticmouseandClaude Opus 4.7 0483f5377d fix(telemetry): silence pynvml deprecation FutureWarning on startup
Fixes #389.

The legacy `pynvml` PyPI package (since version 13.x) registers a
meta-path-finder shim — `_pynvml_redirector.py` — that prints a
`FutureWarning("The pynvml package is deprecated. Please install
nvidia-ml-py instead.")` on every `import pynvml`, even when the
caller's project doesn't depend on pynvml directly. The warning was
firing on every `jarvis --version` / `jarvis ask` / any command that
touches the telemetry path.

Two-layer fix:

1. **pyproject.toml**: switch `pynvml>=13.0.1` → `nvidia-ml-py>=12.560.30`
   in the core deps, `gpu-metrics` extra, and `energy-all` extra.
   `nvidia-ml-py` is NVIDIA's official package and ships the same
   `pynvml` module name without the redirector shim, so the warning
   doesn't fire.

2. **Defensive filters** at all four `import pynvml` sites
   (`telemetry/gpu_monitor.py`, `telemetry/energy_nvidia.py`,
   `server/research_router.py`, `evals/backends/external/_subprocess_runner.py`):
   wrap the import in a narrowly-scoped `warnings.filterwarnings("ignore",
   message=r"The pynvml package is deprecated.*", category=FutureWarning)`.
   Belt-and-suspenders for the case where `pynvml` gets pulled in
   transitively by torch / vllm / etc. — the user's environment may
   still have it installed even if our deps don't pull it in.

Verified locally:
- `uv sync` swaps pynvml → nvidia-ml-py.
- `python -c "import warnings; warnings.simplefilter('error', FutureWarning); from openjarvis.telemetry import gpu_monitor"` → no warning fires (would raise if it did).
- `jarvis --version` → clean output, no FutureWarning preceding the version string.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 15:20:12 +00:00
krypticmouseandClaude Opus 4.7 2d6d6ed7bd fix(packaging): anchor traces/ gitignore pattern so hatch ships it in the wheel
Fixes #372.

The `.gitignore` had `traces/` (unanchored), which matches any directory
named `traces/` anywhere in the tree — including the runtime module at
`src/openjarvis/traces/`. hatchling honors `.gitignore` when building
the wheel, so it silently dropped the entire `openjarvis/traces/`
package.

Effect: every fresh `pip install openjarvis==1.0.1` failed at import
time with `ModuleNotFoundError: No module named 'openjarvis.traces'`
the moment the user touched `jarvis ask`, learning, or the server.
Confirmed by @gilbert-barajas with a clean repro on macOS Apple Silicon.

Reproduced locally by running `uv build --wheel` on a clean checkout
of `main`:
- Before this change: `openjarvis/traces/` absent from the wheel.
- After this change: all 4 expected files present
  (`__init__.py`, `analyzer.py`, `collector.py`, `store.py`).

Anchored the pattern to `/traces/` so it only matches a top-level
`traces/` directory (where ad-hoc trace dumps may live during
development), not any nested `traces/` subdir. Added a comment in the
gitignore explaining the gotcha so it doesn't recur.

The other unanchored directory patterns in the file (`results/`,
`logs/`, `htmlcov/`, `site/`, `build/`, `dist/`, `venv/`, `env/`)
were audited — none collide with any directory currently under
`src/openjarvis/`. Left them unanchored to keep the diff minimal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 15:17:12 +00:00
Robby ManihaniandGitHub 71c5b2bce1 feat(cli): arc-reactor startup banner for init/serve/ask (#397) 2026-05-23 07:57:32 -07:00
github-actions[bot] 440915c822 chore: update clone traffic data [skip ci] 2026-05-23 06:58:07 +00:00