Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
21955c6
feat(engine): add workflows Phase 1 data layer and Windows libsql-ffi…
Redooz Jun 6, 2026
3312739
chore: stop tracking vendor/libsql-ffi
Redooz Jun 6, 2026
0dbb5b4
Merge pull request #1 from Redooz/phase-1
Redooz Jun 6, 2026
089c669
fix(engine): restore local libsql-ffi patch for Windows builds
Redooz Jun 6, 2026
d5492d6
Merge pull request #2 from Redooz/fix/libsql-ffi-local-vendor
Redooz Jun 6, 2026
b660a02
feat(engine): workflows phase 2 planner, executor, and REST API
Redooz Jun 6, 2026
d75d3c7
Merge pull request #3 from Redooz/workflows-phase-2
Redooz Jun 6, 2026
5954400
feat: add workflows tab UI and run dashboard (phase 4)
Redooz Jun 6, 2026
38b77b9
Merge pull request #4 from Redooz/claude/phase-4-workflows
Redooz Jun 6, 2026
a8a8513
feat(engine): mid-run workflow approval gates and approved-step execu…
Redooz Jun 6, 2026
acfc6a3
feat(engine): inline workflow runs, chat triggers, and question support
Redooz Jun 8, 2026
98c60d9
feat(ui/chat): question and workflow-run message cards
Redooz Jun 8, 2026
c00c93d
feat(ui/workflows): extract shared run-content and add inline run card
Redooz Jun 8, 2026
17c0693
feat(app): render inline question and workflow-run cards in chat
Redooz Jun 8, 2026
faecce6
docs: document inline workflows, questions, and internals slides
Redooz Jun 8, 2026
015a53a
fix: keep workflow plans and summaries in the user's chat language
Redooz Jun 8, 2026
1e070b2
fix: hide execution status on saved workflow steps
Redooz Jun 9, 2026
f2dc1a7
Merge pull request #5 from Redooz/claude/fix-saved-step-status
Redooz Jun 9, 2026
7ddd23a
feat: promote inline workflow runs and improve run panels
Redooz Jun 9, 2026
bc170a1
chore: remove Windows workflow smoke scripts from branch
Redooz Jun 9, 2026
650fb20
Merge pull request #6 from Redooz/feat/workflow-inline-promote-panel
Redooz Jun 9, 2026
0645cb6
feat(workflows): show Composio connect cards when workflow steps need…
Redooz Jun 10, 2026
07284c2
Merge pull request #7 from Redooz/claude/workflow-composio-connection…
Redooz Jun 10, 2026
96904e4
feat(workflows): plan approval from chat and run UI
Redooz Jun 11, 2026
0155295
Merge pull request #8 from Redooz/claude/workflow-plan-approval-chat
Redooz Jun 11, 2026
c51465f
Delete GEMINI.md
Redooz Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ app/src-tauri/resources/bin/

# Houston engine sidecar staged by build.rs (built from source in CI, not committed)
app/src-tauri/binaries/

# Local libsql-ffi vendoring for Windows (patched build.rs; not committed)
vendor/
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ Need specific knowledge? Load on demand:
- Colors, typography, components, animation → `knowledge-base/design-system.md`
- `.houston/` layout, schemas, reactivity → `knowledge-base/files-first.md`
- Skills on disk + UI, picker, invocation marker → `knowledge-base/skills.md`
- Workflows (saved + inline runs, chat markers, inline panel) → `knowledge-base/workflows.md`
- Agent manifest, tiers, sidebar, workspaces → `knowledge-base/agent-manifest.md`
- Engine wire protocol (REST + WS) → `knowledge-base/engine-protocol.md`
- Provider error taxonomy + classifier contract → `knowledge-base/provider-errors.md`
Expand Down
23 changes: 11 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ houston-engine-core = { version = "0.4.19", path = "engine/houston-engine-core"
houston-engine-protocol = { version = "0.4.19", path = "engine/houston-engine-protocol" }
houston-engine-server = { version = "0.4.19", path = "engine/houston-engine-server" }

[patch.crates-io]
# Patched build.rs (std::fs::copy instead of Unix cp). vendor/libsql-ffi is
# gitignored — run scripts/setup-libsql-ffi-vendor.sh before building on a
# fresh clone.
libsql-ffi = { path = "vendor/libsql-ffi" }

# Keep line-table debug info in release binaries so Sentry can symbolicate
# Rust panics to file:line. Costs ~10-15% binary size; full debug info is
# stripped, only line tables remain. sentry-cli debug-files upload extracts
Expand Down
1 change: 1 addition & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@houston-ai/layout": "workspace:*",
"@houston-ai/review": "workspace:*",
"@houston-ai/routines": "workspace:*",
"@houston-ai/workflows": "workspace:*",
"@houston-ai/skills": "workspace:*",
"@sentry/browser": "^10.54.0",
"@supabase/supabase-js": "^2.45.0",
Expand Down
21 changes: 21 additions & 0 deletions app/src-tauri/src/houston_prompt/integrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ Quick reference:\n\
- `composio search \"<what you want to do>\"` - find the right tool\n\
- `composio execute <TOOL_SLUG> -d '{ ... }'` - run a tool\n\
- `composio execute <TOOL_SLUG> --get-schema` - see required params\n\n\
**Execute rules (all platforms):** always pass tool arguments as inline JSON on \
the `-d` flag, e.g. `composio execute GMAIL_FETCH_EMAILS -d '{\"max_results\":10}'`. \
Do NOT pipe multiline JSON via shell here-strings or `| composio ... -d -` unless \
you are on bash and have verified the pipe works. Judge success by exit code and \
stdout JSON, not stderr text.\n\n\
Search first, inspect the schema when needed, then execute only after the \
interaction procedure says the task is ready.\n\n\
## When the user is not signed into Composio at all\n\n\
Expand Down Expand Up @@ -45,3 +50,19 @@ to go to the Integrations tab. Instead:\n\n\
approve access in the browser, I'll keep going from here \
automatically.\" Then stop and wait. When Houston's confirmation \
arrives, retry the original request.";

/// Extra Composio guidance appended on Windows only (PowerShell stderr quirks).
#[cfg(windows)]
pub const COMPOSIO_WINDOWS_SHELL: &str = "\n\n## Windows PowerShell\n\n\
On Windows, shell commands may run through PowerShell. PowerShell treats ANY \
stderr from native programs (including composio) as a `NativeCommandError`, \
even when the command succeeded. Composio may print \"Update available\" to \
stderr. Ignore that banner; check exit code and stdout JSON instead.\n\n\
- Use single-line commands: `composio execute <TOOL> -d '{\"max_results\":10}'`\n\
- Do NOT use `'@ ... '@ | composio execute ... -d -` (here-strings break easily)\n\
- If stderr pollutes the captured output, prefix: \
`$ErrorActionPreference='Continue'; composio execute ...`\n\
- `CI=1` is already set in the environment Houston provides";

#[cfg(not(windows))]
pub const COMPOSIO_WINDOWS_SHELL: &str = "";
70 changes: 68 additions & 2 deletions app/src-tauri/src/houston_prompt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,24 @@ mod integrations;
mod onboarding;
mod routines;
mod skills_memory;
mod questions;
mod workflows;

pub use base::HOUSTON_SYSTEM_PROMPT;
pub use integrations::COMPOSIO_GUIDANCE;
pub use onboarding::ONBOARDING_GUIDANCE;
pub use routines::ROUTINES_GUIDANCE;
pub use skills_memory::SELF_IMPROVEMENT_GUIDANCE;
pub use questions::QUESTIONS_GUIDANCE;
pub use workflows::WORKFLOWS_GUIDANCE;

/// Build the composite system prompt the engine uses as its fallback.
/// Order: base identity, skills/memory guidance, routines guidance, Composio guidance.
/// Order: base identity, skills/memory guidance, routines guidance, workflows guidance, Composio guidance.
pub fn system_prompt() -> String {
format!(
"{HOUSTON_SYSTEM_PROMPT}\n\n---\n\n{SELF_IMPROVEMENT_GUIDANCE}\n\n---\n\n{ROUTINES_GUIDANCE}{COMPOSIO_GUIDANCE}"
"{HOUSTON_SYSTEM_PROMPT}\n\n---\n\n{SELF_IMPROVEMENT_GUIDANCE}\n\n---\n\n{ROUTINES_GUIDANCE}\n\n---\n\n{WORKFLOWS_GUIDANCE}\n\n---\n\n{QUESTIONS_GUIDANCE}{}{}",
COMPOSIO_GUIDANCE,
integrations::COMPOSIO_WINDOWS_SHELL,
)
}

Expand Down Expand Up @@ -89,4 +95,64 @@ mod tests {
prompt.contains("Ask for approval before creating, enabling, or changing a Routine")
);
}

#[test]
fn workflow_guidance_describes_trigger_marker() {
let prompt = system_prompt();

assert!(prompt.contains("## How-To Guidance: Workflows"));
assert!(prompt.contains("<!--houston:workflow "));
assert!(prompt.contains("workflowId"));
assert!(prompt.contains("planPrompt"));
assert!(prompt.contains("Do not start a Workflow"));
}

#[test]
fn workflow_guidance_auto_detects_multi_step_and_clarifies_first() {
let prompt = system_prompt();

assert!(prompt.contains("more than 3 distinct actions"));
assert!(prompt.contains("run in parallel"));
assert!(prompt.contains("## Clarify before planning"));
assert!(prompt.contains("structured question marker"));
assert!(prompt.contains(
"Do not emit a workflow marker on a turn where you are still asking questions"
));
assert!(prompt.contains("fold the user's answers into `planPrompt`"));
}

#[test]
fn workflow_guidance_requires_plan_language_match_chat() {
let prompt = system_prompt();

assert!(prompt.contains(
"Write `planPrompt`, `name`, and `description` in the user's current chat language"
));
assert!(prompt.contains("Keep brand names and code identifiers untranslated"));
}

#[test]
fn questions_guidance_describes_question_marker() {
let prompt = system_prompt();

assert!(prompt.contains("## How-To Guidance: Structured questions"));
assert!(prompt.contains("<!--houston:question "));
assert!(prompt.contains("allowFreeText"));
assert!(prompt.contains("Emit at most one question marker per reply"));
}

#[test]
fn composio_guidance_requires_inline_json() {
let prompt = system_prompt();
assert!(prompt.contains("inline JSON on"));
assert!(prompt.contains("GMAIL_FETCH_EMAILS"));
}

#[cfg(windows)]
#[test]
fn composio_guidance_includes_powershell_notes_on_windows() {
let prompt = system_prompt();
assert!(prompt.contains("## Windows PowerShell"));
assert!(prompt.contains("NativeCommandError"));
}
}
20 changes: 20 additions & 0 deletions app/src-tauri/src/houston_prompt/questions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/// Guidance for structured in-chat questions the user answers via a card.
pub const QUESTIONS_GUIDANCE: &str = r#"## How-To Guidance: Structured questions

When you need a discrete decision from the user (scope, priority, preference, or missing detail), ask with Houston's structured question card instead of a long plain-text list.

How to ask:
1. Write one short user-voice sentence introducing what you need.
2. Append a single internal marker (HTML comment) carrying the questions JSON. Houston renders it as an interactive card. Never show or describe the marker.
3. Stop and wait for the user's answer. Do not continue planning or acting on the same turn.

Marker shape (generate a fresh `id` per question set):
<!--houston:question {"id":"<uuid>","questions":[{"id":"q1","prompt":"<question>","options":[{"id":"1","label":"<choice>"},{"id":"2","label":"<choice>"}],"allowMultiple":false,"allowFreeText":true}]}-->

Rules:
- Keep options short and mutually exclusive unless `allowMultiple` is true.
- Use `allowFreeText: true` when a custom answer is reasonable (renders a "Type something" row).
- You may include several questions in one marker; the card paginates them.
- Emit at most one question marker per reply.
- After the user answers, continue using their choices. Do not re-ask unless something material changed.
"#;
58 changes: 58 additions & 0 deletions app/src-tauri/src/houston_prompt/workflows.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/// Workflows guidance: multi-step plan-approve-execute runs triggered from chat.
pub const WORKFLOWS_GUIDANCE: &str = r#"## How-To Guidance: Workflows

Workflows are multi-step runs Houston plans, the user approves, then executes step by step. Use a Workflow when the user's request is too large or complex to handle as a single chat action.

Start a Workflow when any of these apply:
- Fulfilling the request takes more than 3 distinct actions.
- Two or more actions have no dependency on each other and could run in parallel.
- The request needs several dependent steps in sequence.

Do not confuse Workflows with other behavior:
- A one-shot answer or simple action (1-3 straightforward steps): just do it in chat. Do not start a Workflow.
- Scheduled or recurring future work: a Routine.
- A reusable manual procedure the user runs themselves: a Skill.
- A multi-step plan-approve-execute run the user wants now: a Workflow.

## Clarify before planning

Before starting a Workflow, fine-tune the plan with the user:
1. Estimate whether the request meets the thresholds above.
2. If it does, ask a short, focused set of clarifying questions using the structured question marker (see Structured questions guidance). A few at most, not an interrogation. Cover scope, priorities, constraints, or missing details that would change the plan.
3. Do not emit a workflow marker on a turn where you are still asking questions. Wait for the user's answers first.
4. If the request is already specific enough to plan well, skip straight to triggering.
5. When you trigger, fold the user's answers into `planPrompt` so the generated plan reflects their preferences.

## Triggering a Workflow

When a Workflow is warranted and you have enough detail, include a single internal marker in your reply. The marker is an HTML comment for Houston only. Never show it to the user or describe it. Pair it with one short user-voice sentence saying you are putting together a plan.

Saved workflow: if one of the workflows under `# Available Workflows` fits, reference it by id:
<!--houston:workflow {"workflowId":"<id>"}-->

New (inline) workflow: when nothing saved fits, describe the work (include clarifications from the user):
<!--houston:workflow {"planPrompt":"<what to plan and do>","name":"<short title>","description":"<one line>"}-->

Rules:
- Emit at most one marker per reply.
- `planPrompt` is required for an inline workflow. Without a saved match and without `planPrompt`, the run is rejected.
- The user approves the generated plan before execution. The marker starts a plan-then-approve flow, not an irreversible action.
- Write `planPrompt`, `name`, and `description` in the user's current chat language (the same language you are speaking to them). The generated plan is shown to the user. Keep brand names and code identifiers untranslated.

## After the plan is shown

When `# Active workflow run (awaiting your review)` is present in your context:

- If the user asks to **change** the plan, emit exactly one replan marker with their feedback folded in:
<!--houston:workflow-replan {"runId":"<id from context>","feedback":"<what to change>"}-->

- If the user clearly confirms they want to **start** (for example "go ahead", "start", "looks good", "run it"), emit exactly one approve marker:
<!--houston:workflow-approve {"runId":"<id from context>"}-->

Rules:
- Use the `runId` from the active workflow run section. Do not guess.
- At most one workflow action marker per reply.
- Never show marker syntax to the user.
- Do not emit a workflow **trigger** marker for a run that is already open and awaiting review.
- Pair the marker with one short user-voice sentence acknowledging the choice.
"#;
1 change: 1 addition & 0 deletions app/src/agents/standard-tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface AgentTab {
export const STANDARD_TABS: AgentTab[] = [
{ id: "activity", label: "Activity", builtIn: "board", badge: "activity" },
{ id: "routines", label: "Routines", builtIn: "routines" },
{ id: "workflows", label: "Workflows", builtIn: "workflows" },
{ id: "files", label: "Files", builtIn: "files" },
{ id: "job-description", label: "Job Description", builtIn: "job-description" },
{ id: "integrations", label: "Integrations", builtIn: "integrations" },
Expand Down
2 changes: 2 additions & 0 deletions app/src/agents/tab-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import FilesTab from "../components/tabs/files-tab";
import IntegrationsTab from "../components/tabs/integrations-tab";
import JobDescriptionTab from "../components/tabs/job-description-tab";
import RoutinesTab from "../components/tabs/routines-tab";
import WorkflowsTab from "../components/tabs/workflows-tab";

const BUILTIN_TABS: Record<string, ComponentType<TabProps>> = {
board: BoardTab,
Expand All @@ -15,6 +16,7 @@ const BUILTIN_TABS: Record<string, ComponentType<TabProps>> = {
integrations: IntegrationsTab,
"job-description": JobDescriptionTab,
routines: RoutinesTab,
workflows: WorkflowsTab,
};

export function resolveTabComponent(tab: AgentTab): ComponentType<TabProps> {
Expand Down
Loading