flowjet 2.0.0__tar.gz → 2.0.2__tar.gz
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.
Potentially problematic release.
This version of flowjet might be problematic. Click here for more details.
- {flowjet-2.0.0 → flowjet-2.0.2}/CHANGELOG.md +49 -0
- flowjet-2.0.2/PKG-INFO +195 -0
- flowjet-2.0.2/README.md +151 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/naming.md +2 -2
- flowjet-2.0.2/docs/server.md +136 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/specs/RFC-003-production-isolation-hardening.md +10 -4
- {flowjet-2.0.0 → flowjet-2.0.2}/pyproject.toml +7 -4
- flowjet-2.0.2/src/flowjet/core/backend.py +107 -0
- flowjet-2.0.2/src/flowjet/core/bootstrap.py +310 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/bridges/nano/adapter.py +7 -6
- flowjet-2.0.2/src/flowjet/core/identity.py +140 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/modes.py +36 -7
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/acp/agent.py +34 -1
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/config.py +11 -1
- flowjet-2.0.0/PKG-INFO +0 -288
- flowjet-2.0.0/README.md +0 -245
- flowjet-2.0.0/src/flowjet/core/bootstrap.py +0 -183
- {flowjet-2.0.0 → flowjet-2.0.2}/.gitignore +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/LICENSE +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/config/nano.yml +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/deploy/README.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/deploy/nano.yml +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/completion-design.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/drafts/README.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/drafts/api-spec.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/impl/IG-001-openai-compatible-server.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/impl/IG-002-isolated-thread-pool-runtime.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/impl/IG-003-production-isolation-hardening.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/impl/README.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/impl/TEST-COVERAGE-MATRIX.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/specs/RFC-001-openai-compatible-api.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/specs/RFC-002-isolated-thread-pool-runtime.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/specs/RFC-004-unified-package.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/specs/rfc-history.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/specs/rfc-index.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/specs/rfc-namings.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/specs/templates/architecture-design.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/specs/templates/conceptual-design.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/specs/templates/impl-interface-design.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/specs/templates/rfc-standard.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/specs/templates/rfc-template.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/docs/upgrade.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/examples/README.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/nano.yml +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/__init__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/__main__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/README.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/gws-drive/SKILL.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/gws-drive-upload/SKILL.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/logo-generator-skill/.env.example +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/logo-generator-skill/README.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/logo-generator-skill/SKILL.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/logo-generator-skill/assets/background_library.html +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/logo-generator-skill/assets/showcase_template.html +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/logo-generator-skill/references/background_styles.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/logo-generator-skill/references/design_patterns.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/logo-generator-skill/references/webgl_backgrounds.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/logo-generator-skill/requirements.txt +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/logo-generator-skill/scripts/generate_showcase.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/logo-generator-skill/scripts/svg_to_png.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/SKILL.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/brainstorming/spec-document-reviewer-prompt.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/implementation/coding-plan-template.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/implementation/impl-guide-template.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/review/pr-review-template.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/review/review-checklist.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/specs/rfc-template.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/specs/template-architecture-design.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/specs/template-conceptual-design.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/specs/template-impl-interface-design.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-drafts-readme.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-impl-readme.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-platonic.yml +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-history.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-index.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-namings.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-standard.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/BRAINSTORM/brainstorm.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-code.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-create-guide.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-full.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-update-guide.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-validate-guide.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-plan-modular-specs.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-recover-architecture.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-recover-conceptual.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-recover-impl-interface.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-scaffold.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-scan.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/REFERENCE.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/REVIEW/review-spec-compliance.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-check-compliance.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-check-taxonomy.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-generate-history.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-generate-index.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-generate-namings.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-refine.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-validate-consistency.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-overview.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-phase-1.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-phase-2.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-phase-3.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/SKILL.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/evidence-deep.json +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/evidence-first.json +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/idea-first.json +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/loop.json +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/paper-pipeline.json +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/rapid.json +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/rigor-first.json +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/stance-first.json +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/systematic-review.json +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/verify-loop.json +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/references/backends.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/references/handoff-ars-omr.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/references/handoff-omr-ars.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/references/routing.md +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/scripts/csljson_to_omr.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/builtin_skills/research-bootstrap/scripts/papers_index_to_csljson.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/__init__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/__main__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/agent.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/cli.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/completion/__init__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/completion/context.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/completion/engine.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/doctor_cmd.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/doctor_fix_cmd.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/progress.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/serve_cmd.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/setup_cmd.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/shell/__init__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/shell/_fj.zsh +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/shell/fj.bash +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/stream.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/threads.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/cli/tool_stream.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/__init__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/backends/__init__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/backends/direct.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/backends/fake.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/backends/isolation/__init__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/backends/isolation/adapter.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/backends/isolation/admission.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/backends/isolation/backend.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/backends/isolation/errors.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/backends/isolation/mode_gate.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/backends/isolation/pool.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/backends/isolation/request.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/backends/isolation/workspace.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/bridges/nano/__init__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/bridges/nano/backend.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/bridges/nano/mapping.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/events.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/protocol.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/tool_results.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/core/tool_stream.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/__init__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/__main__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/acp/__init__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/acp/routes.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/http/__init__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/http/app.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/http/auth.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/openai_compat/__init__.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/openai_compat/errors.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/openai_compat/projection.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/openai_compat/routes.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/openai_compat/schemas.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/openai_compat/service.py +0 -0
- {flowjet-2.0.0 → flowjet-2.0.2}/src/flowjet/server/openai_compat/store.py +0 -0
|
@@ -8,6 +8,55 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
8
8
|
> History from 0.1.0–0.2.0 below was released as the separate `flowjet-server`
|
|
9
9
|
> distribution, now merged into `flowjet`. See [docs/upgrade.md](docs/upgrade.md).
|
|
10
10
|
|
|
11
|
+
## [Unreleased]
|
|
12
|
+
|
|
13
|
+
## [2.0.2] — 2026-09-18
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **Duo backends — `soothe` or `soothe-nano`.** `FLOWJET_BACKEND` (CLI, default
|
|
18
|
+
`soothe`) and `FLOWJET_SERVER_BACKEND` (HTTP/ACP, default `nano`) select which
|
|
19
|
+
runtime builds the agent. `soothe` is a host layer over soothe-nano, so the
|
|
20
|
+
engine stays installed either way; the two surfaces switch independently
|
|
21
|
+
because the server needs a dual-mode agent (AGENT + ASK graphs per request),
|
|
22
|
+
which soothe does not expose — with `FLOWJET_SERVER_BACKEND=soothe` the server
|
|
23
|
+
builds one host agent per mode and routes on `interaction_mode`.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- The CLI now builds its agent through the `soothe` host runtime by default
|
|
28
|
+
(host middleware, `request_plan_mode` / `ask_user` tools, configurable
|
|
29
|
+
persona). Set `FLOWJET_BACKEND=nano` for the previous behaviour.
|
|
30
|
+
|
|
31
|
+
## [2.0.1] — 2026-09-17
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- **ACP sessions run in the client's directory.** `FlowJetAcpAgent` now records
|
|
36
|
+
the `cwd` from `session/new`, `session/load`, `session/resume` and
|
|
37
|
+
`session/fork` and forwards it as the run's `metadata.workspace`. Previously
|
|
38
|
+
the client `cwd` was accepted and discarded, so every ACP session ran in a
|
|
39
|
+
hashed workspace under `FLOWJET_HOME`.
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- **The assistant identifies as FlowJet, not Soothe.** soothe-nano prepends its
|
|
44
|
+
own `<ASSISTANT_IDENTITY>` block — "a helpful AI assistant" named `Soothe` —
|
|
45
|
+
to every system prompt tier, and only parameterises it by `agent.name`.
|
|
46
|
+
`flowjet.core.identity` now installs a FlowJet template (coding agent, creator
|
|
47
|
+
line, and an explicit "never identify as Soothe / soothe-nano / Claude /
|
|
48
|
+
ChatGPT / Gemini / Anthropic / OpenAI / Google" rule) and `apply_profile`
|
|
49
|
+
defaults `agent.name` to `FlowJet` on both the CLI and server surfaces. An
|
|
50
|
+
explicit `agent.name` or `agent.system_prompt` in `nano.yml` still wins.
|
|
51
|
+
- **Workspace resolution is caller-driven by default.**
|
|
52
|
+
`FLOWJET_ALLOW_EXTERNAL_WORKSPACE` now defaults to `true`, so a workspace
|
|
53
|
+
outside `FLOWJET_HOME` is honoured rather than rejected. This is not a
|
|
54
|
+
sandbox escape — tools remain confined to whichever workspace is selected
|
|
55
|
+
(`allow_paths_outside_workspace` is still `false`); the boundary moves to the
|
|
56
|
+
caller's directory instead of disappearing. Set
|
|
57
|
+
`FLOWJET_ALLOW_EXTERNAL_WORKSPACE=false` to restore forced hashed
|
|
58
|
+
per-session workspaces.
|
|
59
|
+
|
|
11
60
|
## [2.0.0] — 2026-09-17 — unified CLI + server
|
|
12
61
|
|
|
13
62
|
**Breaking.** `flowjet-server` is merged into this repository and ships as one
|
flowjet-2.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: flowjet
|
|
3
|
+
Version: 2.0.2
|
|
4
|
+
Summary: FlowJet — agent CLI (fj) and server (ACP + OpenAI-compatible HTTP) powered by soothe-nano
|
|
5
|
+
Project-URL: Homepage, https://github.com/caesar0301/flowjet
|
|
6
|
+
Project-URL: Repository, https://github.com/caesar0301/flowjet
|
|
7
|
+
Project-URL: Issues, https://github.com/caesar0301/flowjet/issues
|
|
8
|
+
Author: Xiaming Chen
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: acp,agent,ai,cli,coding-agent,fj,flowjet,nano,openai,server,soothe
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Environment :: Web Environment
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Requires-Python: <3.15,>=3.11
|
|
25
|
+
Requires-Dist: soothe-nano<1.3.0,>=1.2.28
|
|
26
|
+
Requires-Dist: soothe<2.0.0,>=1.0.12
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: httpx>=0.27.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: openai>=2.51.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest-asyncio>=1.3.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: ruff>=0.12.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: twine>=5.0.0; extra == 'dev'
|
|
36
|
+
Provides-Extra: server
|
|
37
|
+
Requires-Dist: agent-client-protocol[http]<1.0.0,>=0.12.1; extra == 'server'
|
|
38
|
+
Requires-Dist: fastapi>=0.115.0; extra == 'server'
|
|
39
|
+
Requires-Dist: langchain-core>=0.3; extra == 'server'
|
|
40
|
+
Requires-Dist: pydantic-settings>=2.0; extra == 'server'
|
|
41
|
+
Requires-Dist: pydantic>=2.0; extra == 'server'
|
|
42
|
+
Requires-Dist: uvicorn[standard]>=0.32.0; extra == 'server'
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
45
|
+
# FlowJet
|
|
46
|
+
|
|
47
|
+
[](https://pypi.org/p/flowjet)
|
|
48
|
+
[](https://pypi.org/p/flowjet)
|
|
49
|
+
[](LICENSE)
|
|
50
|
+
|
|
51
|
+
**FlowJet** is a coding agent you can run two ways:
|
|
52
|
+
|
|
53
|
+
- **`fj`** — ask a question in your terminal, get an answer. No UI, no context-switching.
|
|
54
|
+
- **`flowjet-server`** — the same agent as a service: **ACP** over WebSocket and an **OpenAI-compatible HTTP API**, so any OpenAI SDK can drive it.
|
|
55
|
+
|
|
56
|
+
It runs on [soothe-nano](https://github.com/mirasoth/soothe-nano) — tools, skills, MCP, subagents — with SQLite persistence, so every conversation is resumable.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Install
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install flowjet # CLI
|
|
64
|
+
pip install 'flowjet[server]' # CLI + HTTP service
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Requires Python 3.11+. The server is an optional extra — installing just `flowjet` pulls a single runtime dependency.
|
|
68
|
+
|
|
69
|
+
## Configure
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
fj setup # guided: pick a local or hosted model
|
|
73
|
+
# or, with no config file at all:
|
|
74
|
+
export OPENAI_API_KEY=sk-...
|
|
75
|
+
fj summarize README.md
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`fj setup` writes `~/.soothe/config/nano.yml`. Without it, FlowJet falls back to `OPENAI_API_KEY` or `ANTHROPIC_API_KEY`.
|
|
79
|
+
|
|
80
|
+
Not sure your machine is ready? `fj doctor` (add `--deep`, `--live-llm`).
|
|
81
|
+
|
|
82
|
+
### Backends
|
|
83
|
+
|
|
84
|
+
Two runtimes can build the agent; they are switched independently per surface:
|
|
85
|
+
|
|
86
|
+
| Env var | Surface | Default | Values |
|
|
87
|
+
|---------|---------|---------|--------|
|
|
88
|
+
| `FLOWJET_BACKEND` | CLI (`fj`) | `soothe` | `soothe`, `nano` |
|
|
89
|
+
| `FLOWJET_SERVER_BACKEND` | `flowjet-server` / `fj serve` | `nano` | `soothe`, `nano` |
|
|
90
|
+
|
|
91
|
+
`soothe` is the host runtime (extra middleware and tools over the same
|
|
92
|
+
soothe-nano engine). The server defaults to `nano` because it needs a dual-mode
|
|
93
|
+
agent — AGENT and ASK graphs selected per request — which `soothe` does not
|
|
94
|
+
expose yet; on `soothe` the server builds one host agent per mode instead.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## CLI
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
fj explain this repo
|
|
102
|
+
fj -f and now add tests # continue this project's latest conversation
|
|
103
|
+
fjf what did we decide? # short alias of fj -f
|
|
104
|
+
fj -l # list recent conversations
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
| Flag | Meaning |
|
|
108
|
+
|------|---------|
|
|
109
|
+
| `-f` / `--follow` | Continue the latest thread in this project |
|
|
110
|
+
| `-t ID` / `--thread` | Continue (or pin) a specific thread — overrides `-f` |
|
|
111
|
+
| `-l` / `--list` | List recent threads (newest first) |
|
|
112
|
+
| `-n NUM` | How many threads `-l` shows (`0` = all) |
|
|
113
|
+
| `-a` / `--ask` | Read-only: answer without touching files |
|
|
114
|
+
| `-v` / `--verbose` | Mirror tool calls on stderr |
|
|
115
|
+
| `-c PATH` / `-w DIR` | Alternate `nano.yml` / workspace root |
|
|
116
|
+
|
|
117
|
+
`-f` is scoped to your current project, so work in other checkouts never hijacks your thread.
|
|
118
|
+
|
|
119
|
+
Enable shell completion (predicts full queries, not just flags):
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
eval "$(fj completion zsh)" # or: fj completion bash
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Server
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
flowjet-server # host :: (dual-stack), port 8618
|
|
131
|
+
fj serve --port 8618 # same, from the CLI
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
from openai import OpenAI
|
|
136
|
+
|
|
137
|
+
client = OpenAI(api_key="local", base_url="http://127.0.0.1:8618/v1")
|
|
138
|
+
print(client.responses.create(model="default", input="Hello"))
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
| Endpoint | Purpose |
|
|
142
|
+
|----------|---------|
|
|
143
|
+
| `POST /v1/responses` | Create a response (`stream=true` → SSE) |
|
|
144
|
+
| `GET` / `DELETE /v1/responses/{id}` | Retrieve / cancel |
|
|
145
|
+
| `POST /v1/chat/completions` | Chat Completions (non-stream + SSE) |
|
|
146
|
+
| `GET /v1/models` | Model ids |
|
|
147
|
+
| `GET /health` | Liveness |
|
|
148
|
+
| `WS /acp` | Agent Client Protocol |
|
|
149
|
+
|
|
150
|
+
Per-request options go in `extra_body.flowjet`:
|
|
151
|
+
|
|
152
|
+
| Field | Values | Meaning |
|
|
153
|
+
|-------|--------|---------|
|
|
154
|
+
| `session` | string | Isolates workspace + conversation thread |
|
|
155
|
+
| `interaction_mode` | `agent` (default) \| `ask` | `ask` is hard read-only |
|
|
156
|
+
| `projection` | `report` \| `progress` \| `developer` | How much SSE detail to expose |
|
|
157
|
+
|
|
158
|
+
Full configuration, environment variables and the security model: [docs/server.md](docs/server.md) · deployment: [deploy/README.md](deploy/README.md).
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Extend
|
|
163
|
+
|
|
164
|
+
Add skills and MCP servers in `nano.yml`:
|
|
165
|
+
|
|
166
|
+
```yaml
|
|
167
|
+
skills:
|
|
168
|
+
- ~/.soothe/skills/my-reviewer
|
|
169
|
+
|
|
170
|
+
mcp_servers:
|
|
171
|
+
- name: filesystem
|
|
172
|
+
transport: stdio
|
|
173
|
+
command: npx
|
|
174
|
+
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Skills are `SKILL.md` files loaded on demand; MCP tools activate on demand by default (`defer: true`).
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
git clone https://github.com/caesar0301/flowjet.git
|
|
185
|
+
cd flowjet
|
|
186
|
+
make sync-dev && make test && make lint
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Upgrading from 1.x
|
|
190
|
+
|
|
191
|
+
Version 2.0 merges the former `flowjet-server` project into this one. The distribution is now `flowjet` and import paths changed. See [docs/upgrade.md](docs/upgrade.md).
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
MIT
|
flowjet-2.0.2/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# FlowJet
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/p/flowjet)
|
|
4
|
+
[](https://pypi.org/p/flowjet)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
**FlowJet** is a coding agent you can run two ways:
|
|
8
|
+
|
|
9
|
+
- **`fj`** — ask a question in your terminal, get an answer. No UI, no context-switching.
|
|
10
|
+
- **`flowjet-server`** — the same agent as a service: **ACP** over WebSocket and an **OpenAI-compatible HTTP API**, so any OpenAI SDK can drive it.
|
|
11
|
+
|
|
12
|
+
It runs on [soothe-nano](https://github.com/mirasoth/soothe-nano) — tools, skills, MCP, subagents — with SQLite persistence, so every conversation is resumable.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install flowjet # CLI
|
|
20
|
+
pip install 'flowjet[server]' # CLI + HTTP service
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Requires Python 3.11+. The server is an optional extra — installing just `flowjet` pulls a single runtime dependency.
|
|
24
|
+
|
|
25
|
+
## Configure
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
fj setup # guided: pick a local or hosted model
|
|
29
|
+
# or, with no config file at all:
|
|
30
|
+
export OPENAI_API_KEY=sk-...
|
|
31
|
+
fj summarize README.md
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`fj setup` writes `~/.soothe/config/nano.yml`. Without it, FlowJet falls back to `OPENAI_API_KEY` or `ANTHROPIC_API_KEY`.
|
|
35
|
+
|
|
36
|
+
Not sure your machine is ready? `fj doctor` (add `--deep`, `--live-llm`).
|
|
37
|
+
|
|
38
|
+
### Backends
|
|
39
|
+
|
|
40
|
+
Two runtimes can build the agent; they are switched independently per surface:
|
|
41
|
+
|
|
42
|
+
| Env var | Surface | Default | Values |
|
|
43
|
+
|---------|---------|---------|--------|
|
|
44
|
+
| `FLOWJET_BACKEND` | CLI (`fj`) | `soothe` | `soothe`, `nano` |
|
|
45
|
+
| `FLOWJET_SERVER_BACKEND` | `flowjet-server` / `fj serve` | `nano` | `soothe`, `nano` |
|
|
46
|
+
|
|
47
|
+
`soothe` is the host runtime (extra middleware and tools over the same
|
|
48
|
+
soothe-nano engine). The server defaults to `nano` because it needs a dual-mode
|
|
49
|
+
agent — AGENT and ASK graphs selected per request — which `soothe` does not
|
|
50
|
+
expose yet; on `soothe` the server builds one host agent per mode instead.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## CLI
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
fj explain this repo
|
|
58
|
+
fj -f and now add tests # continue this project's latest conversation
|
|
59
|
+
fjf what did we decide? # short alias of fj -f
|
|
60
|
+
fj -l # list recent conversations
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
| Flag | Meaning |
|
|
64
|
+
|------|---------|
|
|
65
|
+
| `-f` / `--follow` | Continue the latest thread in this project |
|
|
66
|
+
| `-t ID` / `--thread` | Continue (or pin) a specific thread — overrides `-f` |
|
|
67
|
+
| `-l` / `--list` | List recent threads (newest first) |
|
|
68
|
+
| `-n NUM` | How many threads `-l` shows (`0` = all) |
|
|
69
|
+
| `-a` / `--ask` | Read-only: answer without touching files |
|
|
70
|
+
| `-v` / `--verbose` | Mirror tool calls on stderr |
|
|
71
|
+
| `-c PATH` / `-w DIR` | Alternate `nano.yml` / workspace root |
|
|
72
|
+
|
|
73
|
+
`-f` is scoped to your current project, so work in other checkouts never hijacks your thread.
|
|
74
|
+
|
|
75
|
+
Enable shell completion (predicts full queries, not just flags):
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
eval "$(fj completion zsh)" # or: fj completion bash
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Server
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
flowjet-server # host :: (dual-stack), port 8618
|
|
87
|
+
fj serve --port 8618 # same, from the CLI
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from openai import OpenAI
|
|
92
|
+
|
|
93
|
+
client = OpenAI(api_key="local", base_url="http://127.0.0.1:8618/v1")
|
|
94
|
+
print(client.responses.create(model="default", input="Hello"))
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
| Endpoint | Purpose |
|
|
98
|
+
|----------|---------|
|
|
99
|
+
| `POST /v1/responses` | Create a response (`stream=true` → SSE) |
|
|
100
|
+
| `GET` / `DELETE /v1/responses/{id}` | Retrieve / cancel |
|
|
101
|
+
| `POST /v1/chat/completions` | Chat Completions (non-stream + SSE) |
|
|
102
|
+
| `GET /v1/models` | Model ids |
|
|
103
|
+
| `GET /health` | Liveness |
|
|
104
|
+
| `WS /acp` | Agent Client Protocol |
|
|
105
|
+
|
|
106
|
+
Per-request options go in `extra_body.flowjet`:
|
|
107
|
+
|
|
108
|
+
| Field | Values | Meaning |
|
|
109
|
+
|-------|--------|---------|
|
|
110
|
+
| `session` | string | Isolates workspace + conversation thread |
|
|
111
|
+
| `interaction_mode` | `agent` (default) \| `ask` | `ask` is hard read-only |
|
|
112
|
+
| `projection` | `report` \| `progress` \| `developer` | How much SSE detail to expose |
|
|
113
|
+
|
|
114
|
+
Full configuration, environment variables and the security model: [docs/server.md](docs/server.md) · deployment: [deploy/README.md](deploy/README.md).
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Extend
|
|
119
|
+
|
|
120
|
+
Add skills and MCP servers in `nano.yml`:
|
|
121
|
+
|
|
122
|
+
```yaml
|
|
123
|
+
skills:
|
|
124
|
+
- ~/.soothe/skills/my-reviewer
|
|
125
|
+
|
|
126
|
+
mcp_servers:
|
|
127
|
+
- name: filesystem
|
|
128
|
+
transport: stdio
|
|
129
|
+
command: npx
|
|
130
|
+
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Skills are `SKILL.md` files loaded on demand; MCP tools activate on demand by default (`defer: true`).
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Development
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
git clone https://github.com/caesar0301/flowjet.git
|
|
141
|
+
cd flowjet
|
|
142
|
+
make sync-dev && make test && make lint
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Upgrading from 1.x
|
|
146
|
+
|
|
147
|
+
Version 2.0 merges the former `flowjet-server` project into this one. The distribution is now `flowjet` and import paths changed. See [docs/upgrade.md](docs/upgrade.md).
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
MIT
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|--------|-------|------|
|
|
11
11
|
| Product brand | **FlowJet** | Human-facing product name |
|
|
12
12
|
| PyPI / `[project].name` | **`flowjet`** | Installable distribution (CLI **and** server) |
|
|
13
|
-
| Source repository | **`flowjet
|
|
13
|
+
| Source repository | **`flowjet`** | GitHub repo (`caesar0301/flowjet`) |
|
|
14
14
|
| Formal CLI | **`flowjet`** | Canonical console entrypoint |
|
|
15
15
|
| CLI alias | **`fj`** | Same as `flowjet` |
|
|
16
16
|
| CLI alias | **`fjf`** | Same as `flowjet -f` / `fj -f` |
|
|
@@ -51,7 +51,7 @@ alias packages. Rationale:
|
|
|
51
51
|
**Cost.** Anyone importing `fj_ai.*` or `flowjet_server.*` must update.
|
|
52
52
|
Migration table: [upgrade.md](upgrade.md).
|
|
53
53
|
|
|
54
|
-
**Not changed.** The
|
|
54
|
+
**Not changed.** The `fj` / `fjf` aliases,
|
|
55
55
|
and the `flowjet-server` console script — so Docker, compose and existing shell
|
|
56
56
|
habits keep working.
|
|
57
57
|
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# FlowJet server reference
|
|
2
|
+
|
|
3
|
+
Everything you need to run `flowjet-server` (or `fj serve`) beyond the
|
|
4
|
+
[quick start in the README](../README.md#server).
|
|
5
|
+
|
|
6
|
+
## Endpoints
|
|
7
|
+
|
|
8
|
+
Base path for the OpenAI-compatible API is `/v1`, so an SDK `base_url` should
|
|
9
|
+
end in `/v1`.
|
|
10
|
+
|
|
11
|
+
| HTTP | OpenAI SDK | Purpose |
|
|
12
|
+
|------|-----------|---------|
|
|
13
|
+
| `GET /health` | — | Liveness + thread-pool metrics |
|
|
14
|
+
| `GET /v1/models` | `client.models.list()` | Logical model ids |
|
|
15
|
+
| `POST /v1/responses` | `client.responses.create(...)` | Create a response |
|
|
16
|
+
| `POST /v1/responses` + SSE | `client.responses.stream(...)` | Streaming response |
|
|
17
|
+
| `GET /v1/responses/{id}` | `client.responses.retrieve(id)` | Retrieve a stored response |
|
|
18
|
+
| `DELETE /v1/responses/{id}` | `client.responses.delete(id)` | Delete + cancel the run |
|
|
19
|
+
| `POST /v1/chat/completions` | `client.chat.completions.create(...)` | Chat Completions (non-stream + SSE) |
|
|
20
|
+
| `WS /acp` | — | Agent Client Protocol (JSON-RPC) |
|
|
21
|
+
|
|
22
|
+
Responses are held in an in-process store; agent conversation state is
|
|
23
|
+
persisted by soothe-nano (SQLite by default, Postgres with `deploy/nano.yml`).
|
|
24
|
+
|
|
25
|
+
## `extra_body.flowjet`
|
|
26
|
+
|
|
27
|
+
| Field | Values | Default | Meaning |
|
|
28
|
+
|-------|--------|---------|---------|
|
|
29
|
+
| `projection` | `report` \| `progress` \| `developer` | `report` | How much SSE detail to expose |
|
|
30
|
+
| `session` | string | new `fj-<uuid>` | Isolates workspace + conversation thread |
|
|
31
|
+
| `interaction_mode` | `agent` \| `ask` | `agent` | `ask` is hard read-only |
|
|
32
|
+
| `metadata` | object | — | Opaque bag forwarded to the runtime |
|
|
33
|
+
|
|
34
|
+
### Projection modes
|
|
35
|
+
|
|
36
|
+
- **`report`** — final answer plus standard OpenAI lifecycle events.
|
|
37
|
+
- **`progress`** — adds `response.flowjet.progress` stages.
|
|
38
|
+
- **`developer`** — adds `response.flowjet.tool.started` / `.completed` summaries.
|
|
39
|
+
|
|
40
|
+
No mode exposes chain-of-thought or tool arguments.
|
|
41
|
+
|
|
42
|
+
### Ask vs agent
|
|
43
|
+
|
|
44
|
+
The service builds nano's dual-mode agent and routes each request by
|
|
45
|
+
`interaction_mode`:
|
|
46
|
+
|
|
47
|
+
| Mode | Behavior |
|
|
48
|
+
|------|----------|
|
|
49
|
+
| `agent` | Full coding agent (read/write tools, shell if enabled in `nano.yml`) |
|
|
50
|
+
| `ask` | Read-only: `ls`, `read_file`, `glob`, `grep`, `file_info` — no writes, no shell |
|
|
51
|
+
|
|
52
|
+
Mode is pinned per session. To switch, start a new session.
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
with client.responses.stream(
|
|
56
|
+
model="default",
|
|
57
|
+
input="Explain how auth works in this workspace.",
|
|
58
|
+
extra_body={"flowjet": {"projection": "progress", "interaction_mode": "ask"}},
|
|
59
|
+
) as stream:
|
|
60
|
+
for event in stream:
|
|
61
|
+
if event.type == "response.flowjet.progress":
|
|
62
|
+
print(event.stage, event.message)
|
|
63
|
+
elif event.type == "response.output_text.delta":
|
|
64
|
+
print(event.delta, end="", flush=True)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Environment
|
|
68
|
+
|
|
69
|
+
| Variable | Default | Meaning |
|
|
70
|
+
|----------|---------|---------|
|
|
71
|
+
| `FLOWJET_API_KEY` | unset | If set, require Bearer auth |
|
|
72
|
+
| `FLOWJET_MODELS` | `default` | Comma-separated logical model ids |
|
|
73
|
+
| `FLOWJET_HOST` | `::` | Bind host (dual-stack IPv4/IPv6) |
|
|
74
|
+
| `FLOWJET_PORT` | `8618` | Bind port |
|
|
75
|
+
| `FLOWJET_HOME` | `~/.flowjet` | Root for per-session workspaces |
|
|
76
|
+
| `FLOWJET_NANO_CONFIG` | unset | Optional `nano.yml` (else `$SOOTHE_HOME/config/nano.yml`) |
|
|
77
|
+
| `FLOWJET_THREAD_POOL_MIN` | `2` | Min isolation worker threads |
|
|
78
|
+
| `FLOWJET_THREAD_POOL_MAX` | `8` | Max isolation worker threads |
|
|
79
|
+
| `FLOWJET_THREAD_POOL_IDLE_TIMEOUT` | `300` | Scaled-worker idle exit seconds (`0` = never) |
|
|
80
|
+
| `FLOWJET_MAX_REQUESTS_PER_WORKER` | `100` | Recycle worker after N turns (`0` = unlimited) |
|
|
81
|
+
| `FLOWJET_REUSE_RUNNER` | `true` | Reuse agent adapter per worker |
|
|
82
|
+
| `FLOWJET_REQUEST_TIMEOUT` | `0` | Per-run timeout seconds (`0` = none — **set this in production**) |
|
|
83
|
+
| `FLOWJET_READY_TIMEOUT` | `30` | Max wait for post-turn worker ready |
|
|
84
|
+
| `FLOWJET_ALLOW_EXTERNAL_WORKSPACE` | `true` | Honour `metadata.workspace` outside `FLOWJET_HOME`; set `false` to force hashed per-session workspaces |
|
|
85
|
+
| `FLOWJET_CORS_ORIGINS` | `*` | Comma-separated browser origins allowed to call the API |
|
|
86
|
+
|
|
87
|
+
## Security model
|
|
88
|
+
|
|
89
|
+
The CLI and the server have deliberately different invariants, declared in
|
|
90
|
+
`flowjet.core.modes` rather than implied by whichever module builds the agent.
|
|
91
|
+
|
|
92
|
+
| | CLI | Server |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `allow_paths_outside_workspace` | `True` (your own machine) | **`False`** — per-request workspace, non-overridable |
|
|
95
|
+
| `bypass` interaction mode | available | **rejected** — tools must never escape the request workspace |
|
|
96
|
+
| Authentication | — | optional `FLOWJET_API_KEY` (Bearer, constant-time comparison) |
|
|
97
|
+
|
|
98
|
+
Notes:
|
|
99
|
+
|
|
100
|
+
- The server forces `allow_paths_outside_workspace = false` even when the
|
|
101
|
+
loaded `nano.yml` asks for wider access.
|
|
102
|
+
- **The workspace itself is caller-chosen by default.** An ACP client's
|
|
103
|
+
`session/new` `cwd`, or `metadata.workspace` on an HTTP request, is honoured
|
|
104
|
+
even outside `FLOWJET_HOME` (`FLOWJET_ALLOW_EXTERNAL_WORKSPACE=true`). That
|
|
105
|
+
moves the confinement boundary to the caller's directory — it does not
|
|
106
|
+
remove it: tools still cannot escape the selected workspace. Set
|
|
107
|
+
`FLOWJET_ALLOW_EXTERNAL_WORKSPACE=false` to reject external paths and force
|
|
108
|
+
the hashed per-session workspace instead.
|
|
109
|
+
- `FLOWJET_CORS_ORIGINS` defaults to `*` with credentials enabled so browser
|
|
110
|
+
clients work out of the box. Set an explicit origin list in production.
|
|
111
|
+
- `/acp` (WebSocket) is unauthenticated unless `FLOWJET_API_KEY` is set;
|
|
112
|
+
put it behind a reverse proxy if you expose it publicly.
|
|
113
|
+
|
|
114
|
+
## Concurrency
|
|
115
|
+
|
|
116
|
+
Each session admits one in-flight request at a time; extra requests for the
|
|
117
|
+
same session queue rather than interleave. Requests execute on a persistent
|
|
118
|
+
thread pool (each worker owns an event loop), so long tool calls never block
|
|
119
|
+
the HTTP loop. Tune with the `FLOWJET_THREAD_POOL_*` variables.
|
|
120
|
+
|
|
121
|
+
The session's workspace is the caller's (`session/new` `cwd`, or
|
|
122
|
+
`metadata.workspace`), falling back to `$FLOWJET_HOME/data/workspaces/ws_<hash>`
|
|
123
|
+
when the caller does not name one.
|
|
124
|
+
|
|
125
|
+
## Deploy
|
|
126
|
+
|
|
127
|
+
Docker image and compose stack (Postgres + pgvector) are in
|
|
128
|
+
[deploy/README.md](../deploy/README.md). The image installs with
|
|
129
|
+
`--extra server` and keeps `CMD ["flowjet-server"]` plus a `:8618/health`
|
|
130
|
+
healthcheck.
|
|
131
|
+
|
|
132
|
+
## Specification
|
|
133
|
+
|
|
134
|
+
- [RFC-001: OpenAI-Compatible API](specs/RFC-001-openai-compatible-api.md)
|
|
135
|
+
- [RFC-002: Isolated Thread-Pool Runtime](specs/RFC-002-isolated-thread-pool-runtime.md)
|
|
136
|
+
- [RFC-003: Production Isolation Hardening](specs/RFC-003-production-isolation-hardening.md)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Status**: Draft
|
|
4
4
|
**Authors**: FlowJet
|
|
5
5
|
**Created**: 2026-07-31
|
|
6
|
-
**Last Updated**: 2026-
|
|
6
|
+
**Last Updated**: 2026-09-17
|
|
7
7
|
**Depends on**: [RFC-002](RFC-002-isolated-thread-pool-runtime.md)
|
|
8
8
|
**Supersedes**: —
|
|
9
9
|
**Kind**: Architecture Design
|
|
@@ -104,11 +104,17 @@ After each turn’s stream task finishes (success, cancel, error, timeout), canc
|
|
|
104
104
|
|
|
105
105
|
### 5.6 Workspace policy
|
|
106
106
|
|
|
107
|
-
1. Default hashed path under `$FLOWJET_HOME/data/workspaces/` —
|
|
107
|
+
1. Default hashed path under `$FLOWJET_HOME/data/workspaces/` — used when the caller names no workspace.
|
|
108
108
|
2. If `metadata.workspace` is set:
|
|
109
|
-
- If `FLOWJET_ALLOW_EXTERNAL_WORKSPACE=true` → resolve/create as today.
|
|
109
|
+
- If `FLOWJET_ALLOW_EXTERNAL_WORKSPACE=true` (**the default**) → resolve/create as today.
|
|
110
110
|
- Else path MUST resolve under `$FLOWJET_HOME` (or equal home); otherwise reject with a clear runtime/OpenAI error (`invalid_workspace`).
|
|
111
111
|
|
|
112
|
+
Revised 2026-09-17: the flag's default flipped from `false` to `true` so a
|
|
113
|
+
desktop ACP client's `session/new` `cwd` is the session workspace without
|
|
114
|
+
requiring configuration. Tool confinement
|
|
115
|
+
(`allow_paths_outside_workspace=false`) is unchanged, so the boundary moves
|
|
116
|
+
to the caller's directory rather than being removed.
|
|
117
|
+
|
|
112
118
|
### 5.7 Interaction mode pin
|
|
113
119
|
|
|
114
120
|
First admitted turn for a `session` records `interaction_mode` (`agent`|`ask`). Later turns with a different mode MUST fail with `interaction_mode_conflict` (HTTP 400). Omitted mode continues the pinned value (default `agent` if never set).
|
|
@@ -139,7 +145,7 @@ Expose a read-only snapshot: `total`, `idle`, `busy`, `dead`, `requests_complete
|
|
|
139
145
|
| `FLOWJET_REUSE_RUNNER` | `true` | Reuse adapter per worker |
|
|
140
146
|
| `FLOWJET_REQUEST_TIMEOUT` | `0` | Per-run timeout (s); production SHOULD set |
|
|
141
147
|
| `FLOWJET_READY_TIMEOUT` | `30` | Ready-barrier timeout (s) |
|
|
142
|
-
| `FLOWJET_ALLOW_EXTERNAL_WORKSPACE` | `
|
|
148
|
+
| `FLOWJET_ALLOW_EXTERNAL_WORKSPACE` | `true` | Honour workspace paths outside `FLOWJET_HOME` (`false` = force hashed per-session workspaces) |
|
|
143
149
|
|
|
144
150
|
---
|
|
145
151
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "flowjet"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.2"
|
|
8
8
|
description = "FlowJet — agent CLI (fj) and server (ACP + OpenAI-compatible HTTP) powered by soothe-nano"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -29,6 +29,9 @@ classifiers = [
|
|
|
29
29
|
# lives in the `server` extra, and `flowjet.cli` never imports it at module
|
|
30
30
|
# scope (see tests/unit/test_cli_no_server_deps.py).
|
|
31
31
|
dependencies = [
|
|
32
|
+
# Default CLI runtime (FLOWJET_BACKEND=soothe). soothe is a host layer over
|
|
33
|
+
# soothe-nano, so nano stays pinned explicitly: soothe only caps it at <2.
|
|
34
|
+
"soothe>=1.0.12,<2.0.0",
|
|
32
35
|
"soothe-nano>=1.2.28,<1.3.0",
|
|
33
36
|
]
|
|
34
37
|
|
|
@@ -74,9 +77,9 @@ fjf = "flowjet.cli.cli:main_follow"
|
|
|
74
77
|
flowjet-server = "flowjet.server.__main__:main"
|
|
75
78
|
|
|
76
79
|
[project.urls]
|
|
77
|
-
Homepage = "https://github.com/caesar0301/flowjet
|
|
78
|
-
Repository = "https://github.com/caesar0301/flowjet
|
|
79
|
-
Issues = "https://github.com/caesar0301/flowjet
|
|
80
|
+
Homepage = "https://github.com/caesar0301/flowjet"
|
|
81
|
+
Repository = "https://github.com/caesar0301/flowjet"
|
|
82
|
+
Issues = "https://github.com/caesar0301/flowjet/issues"
|
|
80
83
|
|
|
81
84
|
[tool.hatch.build.targets.wheel]
|
|
82
85
|
packages = ["src/flowjet"]
|