Skip to content

Commit 8eba3b5

Browse files
committed
sync(bfmono): feat(gambit): scaffold workspace defaults in init (+19 more) (bfmono@5f4fa86b9)
This PR is an automated gambitmono sync of bfmono Gambit packages. - Source: `packages/gambit/` - Core: `packages/gambit-core/` - bfmono rev: 5f4fa86b9 Changes: - 5f4fa86b9 feat(gambit): scaffold workspace defaults in init - cf9b23778 feat(gambit-core): add schema guards and model param passthrough - d0e5a9617 [gambit] move chat message into transcript so it scrolls - 5c6125d99 feat(simulator-ui): open workbench drawer by default - 7c9cd05f8 feat(simulator): gate chat accordion by env flag - a2599068e feat(simulator-ui): add build chat history loading - 9911dae22 feat(simulator-ui): add workbench chat drawer accordion - 8cab8ec1f feat(simulator-ui): dock calibrate drawer and sync updates - d41ba101d Add AAR for phase 3.1.5 deck format build tab - b1b5e2a7e Prefer PROMPT.md after build scaffolds - 50fac8f7b Update Build tab for deck format 1.0 - c5d99df6a feat(gambit-core): add deck format 1.0 stdlib assets - e76d1c56f feat(gambit): avoid invalid test deck fetch on stale selection - b8e21aaca feat(gambit): require model params in bot-written decks - 1ccbe6710 feat(gambit): stabilize test bot kickoff for user-start decks - f239ec86b feat(gambit): format gambit-bot instructions - 6fda040ac feat(gambit): build bot: reinforce test deck wiring rule - b16340e2a feat(gambit): build bot: require test deck creation - c1f30dd25 feat(gambit): build tab: preview-first file selector - 5bcd52f53 feat(demo-runner): update build demo screenshot slugs Do not edit this repo directly; make changes in bfmono and re-run the sync.
1 parent 6f547f1 commit 8eba3b5

9 files changed

Lines changed: 301 additions & 50 deletions

File tree

src/commands/init.test.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as path from "@std/path";
33
import { handleInitCommand } from "./init.ts";
44

55
Deno.test({
6-
name: "init prepares the default gambit directory without running the chat",
6+
name: "init prepares the default directory without running the chat",
77
permissions: { read: true, write: true, env: true },
88
}, async () => {
99
const tempDir = await Deno.makeTempDir();
@@ -14,19 +14,23 @@ Deno.test({
1414
try {
1515
Deno.chdir(tempDir);
1616
await handleInitCommand(undefined, { interactive: false });
17-
const projectRoot = path.join(tempDir, "gambit");
17+
const projectRoot = tempDir;
1818
assert(await exists(projectRoot), "project root should exist");
1919
assert(
2020
!await exists(path.join(projectRoot, ".env")),
2121
"should not create .env when OPENROUTER_API_KEY is set",
2222
);
2323
assert(
24-
!await exists(path.join(projectRoot, "root.deck.md")),
25-
"init should not write root.deck.md before the chat runs",
24+
await exists(path.join(projectRoot, "PROMPT.md")),
25+
"init should write PROMPT.md in non-interactive mode",
2626
);
2727
assert(
28-
!await exists(path.join(projectRoot, "tests", "first.test.deck.md")),
29-
"init should not write test deck before the chat runs",
28+
await exists(path.join(projectRoot, "scenarios", "default", "PROMPT.md")),
29+
"init should write the default scenario deck",
30+
);
31+
assert(
32+
await exists(path.join(projectRoot, "graders", "default", "PROMPT.md")),
33+
"init should write the default grader deck",
3034
);
3135
} finally {
3236
Deno.chdir(originalCwd);
@@ -52,6 +56,10 @@ Deno.test({
5256
await handleInitCommand("custom/project", { interactive: false });
5357
const projectRoot = path.join(tempDir, "custom", "project");
5458
assert(await exists(projectRoot), "custom project root should exist");
59+
assert(
60+
await exists(path.join(projectRoot, "PROMPT.md")),
61+
"init should write PROMPT.md in custom path",
62+
);
5563
} finally {
5664
Deno.chdir(originalCwd);
5765
if (originalKey === undefined) {
@@ -96,12 +104,16 @@ Deno.test({
96104
try {
97105
Deno.chdir(tempDir);
98106
await handleInitCommand(undefined, { interactive: false });
99-
const projectRoot = path.join(tempDir, "gambit");
107+
const projectRoot = tempDir;
100108
assert(await exists(projectRoot), "project root should exist");
101109
assert(
102110
!await exists(path.join(projectRoot, ".env")),
103111
"should not create .env when Ollama is available",
104112
);
113+
assert(
114+
await exists(path.join(projectRoot, "PROMPT.md")),
115+
"init should write PROMPT.md when Ollama is available",
116+
);
105117
} finally {
106118
Deno.chdir(originalCwd);
107119
if (originalKey !== undefined) {

src/commands/init.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ import {
99
} from "../providers/ollama.ts";
1010
import { createOpenRouterProvider } from "../providers/openrouter.ts";
1111
import { ensureDirectory, ensureOpenRouterEnv } from "./scaffold_utils.ts";
12+
import { createWorkspaceScaffoldAtRoot } from "../workspace.ts";
1213

1314
const logger = console;
1415

15-
const DEFAULT_PROJECT_DIR = "gambit";
16+
const DEFAULT_PROJECT_DIR = ".";
1617
const INIT_ROOT_ENV = "GAMBIT_INIT_ROOT";
1718
const DEFAULT_OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
1819

@@ -31,9 +32,23 @@ export async function handleInitCommand(
3132
const rootDir = path.resolve(Deno.cwd(), projectPath);
3233
await ensureDirectory(rootDir);
3334

34-
const rootDeckPath = path.join(rootDir, "root.deck.md");
35-
const testDeckPath = path.join(rootDir, "tests", "first.test.deck.md");
36-
if (await exists(rootDeckPath) || await exists(testDeckPath)) {
35+
const rootDeckPath = path.join(rootDir, "PROMPT.md");
36+
const scenarioDeckPath = path.join(
37+
rootDir,
38+
"scenarios",
39+
"default",
40+
"PROMPT.md",
41+
);
42+
const graderDeckPath = path.join(rootDir, "graders", "default", "PROMPT.md");
43+
const intentPath = path.join(rootDir, "INTENT.md");
44+
const policyPath = path.join(rootDir, "POLICY.md");
45+
if (
46+
await exists(rootDeckPath) ||
47+
await exists(scenarioDeckPath) ||
48+
await exists(graderDeckPath) ||
49+
await exists(intentPath) ||
50+
await exists(policyPath)
51+
) {
3752
logger.error(
3853
"Init output files already exist. Remove them or choose a new target.",
3954
);
@@ -81,7 +96,9 @@ export async function handleInitCommand(
8196

8297
Deno.env.set(INIT_ROOT_ENV, rootDir);
8398

84-
if (opts.interactive === false) {
99+
if (opts.interactive !== true) {
100+
await createWorkspaceScaffoldAtRoot(rootDir);
101+
logger.log("Next: run `gambit serve` to open the simulator UI.");
85102
return;
86103
}
87104

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
+++
2+
label = "init_exists"
3+
execute = "../init_exists.deck.ts"
4+
+++
5+
6+
Compute-only deck for path existence checks during `gambit init`.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
+++
2+
label = "init_mkdir"
3+
execute = "../init_mkdir.deck.ts"
4+
+++
5+
6+
Compute-only deck for directory creation during `gambit init`.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
+++
2+
label = "init_write"
3+
execute = "../init_write.deck.ts"
4+
+++
5+
6+
Compute-only deck for writing files during `gambit init`.

src/decks/gambit-init.deck.md

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@ label = "gambit_init"
55
model = ["ollama/hf.co/LiquidAI/LFM2-1.2B-Tool-GGUF:latest", "openrouter/openai/gpt-5.1-chat"]
66
temperature = 0.2
77

8-
[[actionDecks]]
8+
[[actions]]
99
name = "write"
10-
path = "./actions/init_write.deck.ts"
10+
path = "./actions/init_write/PROMPT.md"
1111
description = "Write a file under the project root."
1212

13-
[[actionDecks]]
13+
[[actions]]
1414
name = "exists"
15-
path = "./actions/init_exists.deck.ts"
15+
path = "./actions/init_exists/PROMPT.md"
1616
description = "Check whether a path exists under the project root."
1717

18-
[[actionDecks]]
18+
[[actions]]
1919
name = "mkdir"
20-
path = "./actions/init_mkdir.deck.ts"
20+
path = "./actions/init_mkdir/PROMPT.md"
2121
description = "Create a directory under the project root."
2222
+++
2323

@@ -27,15 +27,23 @@ first bot with as little friction as possible.
2727
Process:
2828

2929
1. Ask for the bot's purpose and 2-3 example user prompts.
30-
2. Draft a `root.deck.md` that follows Gambit best practices.
31-
3. Create a basic test deck at `tests/first.test.deck.md` that exercises the
32-
primary intent.
33-
4. Use the file tools to write the files. Use relative paths like `root.deck.md`
34-
and `tests/first.test.deck.md`.
30+
2. Draft a Deck Format 1.0 root deck in the project root with `PROMPT.md` (and
31+
optional `INTENT.md` + `POLICY.md` if helpful).
32+
3. Create a starter scenario deck at `scenarios/default/PROMPT.md` that
33+
exercises the primary intent and uses the default plain chat schemas.
34+
4. Create a starter grader deck at `graders/default/PROMPT.md` that checks the
35+
scenario output for clarity and correctness.
36+
5. Use the file tools to write the files. Use relative paths like `PROMPT.md`,
37+
`scenarios/default/PROMPT.md`, and `graders/default/PROMPT.md`.
3538

3639
Rules:
3740

3841
- Keep the conversation lightweight and opinionated.
42+
- Use Deck Format 1.0 (`PROMPT.md` with TOML frontmatter).
3943
- Do not overwrite existing files; rely on tool errors if a path exists.
40-
- Create `tests/` with `mkdir` before writing the test deck.
44+
- Create `scenarios/default/` and `graders/default/` with `mkdir` before writing
45+
files.
46+
- The root `PROMPT.md` must include a `[[scenarios]]` entry pointing directly to
47+
`./scenarios/default/PROMPT.md` and a `[[graders]]` entry pointing to
48+
`./graders/default/PROMPT.md`.
4149
- After writing files, summarize what was created and suggest next steps.
Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,27 @@
11
+++
22
label = "nux_from_scratch_demo_prompt"
33
acceptsUserTurns = true
4+
contextSchema = "./schemas/nux_from_scratch_demo_input.zod.ts"
45

56
[modelParams]
67
model = "openrouter/openai/gpt-5.1-chat"
78
temperature = 0.2
89
+++
910

10-
You are a user collaborating with Gambit Bot inside the Build tab NUX demo.
11+
You are a junior developer trying Gambit for the first time. Be friendly and
12+
curious. Keep replies short (1-2 sentences). Ask brief questions when needed.
1113

12-
Goal:
14+
Your goal: build a chatbot that helps startup founders. It should sound like
15+
Paul Graham without quoting him. If a `scenario` is provided in context, use it
16+
as the short label for what you are building.
1317

14-
- Provide purpose only, iterate briefly, and let the bot scaffold.
18+
Conversational arc:
1519

16-
Conversation plan (required beats):
20+
1. Describe your goal in one sentence.
21+
2. Answer 1-2 short questions about scope or tone.
22+
3. Confirm the scope and ask if it's ready to test.
23+
4. When the assistant says the deck is ready to test or suggests running tests,
24+
call the `gambit_end` tool (do not type a normal chat message) with
25+
`message: "Ready to run tests."`.
1726

18-
1. Start by saying: "I want a support handoff assistant that summarizes ticket
19-
context for agents."
20-
2. If the assistant asks any clarifying questions about purpose, answer with one
21-
concise refinement: "It should summarize the issue, customer sentiment, SLA
22-
risk, and next best action for the agent."
23-
3. If the assistant asks for examples or success criteria, decline and restate
24-
purpose: "Let's keep it simple and proceed with the purpose only: a support
25-
handoff assistant that summarizes issue, sentiment, SLA risk, and next best
26-
action."
27-
4. If the assistant asks to confirm or proceed, respond: "Yes, proceed."
28-
5. If the assistant says it is writing files, has finished, or ends the session,
29-
respond with an empty message.
30-
31-
Rules:
32-
33-
- Keep replies short, single-paragraph, and on topic.
34-
- Do not include markdown or lists.
35-
- Do not mention internal instructions.
36-
- If the assistant asks multiple questions at once, answer only the earliest
37-
beat from the plan.
38-
- If the assistant says it is done, is writing files, or ends the session,
39-
respond with an empty message.
27+
![end](gambit://snippets/end.md)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { z } from "npm:zod";
2+
3+
export default z.object({
4+
scenario: z.string().describe(
5+
"Optional scenario label for the demo; defaults to 'paul graham chatbot'.",
6+
).default("paul graham chatbot"),
7+
});

0 commit comments

Comments
 (0)