Got it. Here’s a one-shot setup that creates everything for you automatically—folders, virtualenv, dependencies, the Bridge server, a sender tool, a run script, a test task, and optional auto-start at login. You only run one PowerShell script and it saves all files for you.
I’m giving you:
A single bootstrap PowerShell script (setup_local_coder_bridge.ps1) that writes all other scripts/files.
The Bridge server (bridge_server.py) that executes safe tasks (write files, make folders, downloads, run whitelisted commands).
A task sender (send_task.ps1) to paste JSON tasks.
A run script (run_bridge.ps1) to start the server.
An optional auto-start scheduled task script.
A sample task JSON.
Run Step 1, and you’re set.
Step 1 — Copy-paste this file and run it
Save the block below as setup_local_coder_bridge.ps1. Then open 64-bit PowerShell as Administrator, cd to the folder where you saved it, and run:
Set-ExecutionPolicy Bypass -Scope Process -Force
.\setup_local_coder_bridge.ps1
It will create everything under C:\tools\LocalCoderBridge and C:\tools\MilkaProjects.
# setup_local_coder_bridge.ps1
# Creates Local Coder Bridge + all scripts, venv, requirements, and a sample task.
# Run in 64-bit PowerShell (Admin recommended).
$ErrorActionPreference = "Stop"
function Confirm-64bit {
if (-not [Environment]::Is64BitProcess) {
Write-Error "This PowerShell is 32-bit. Open the 64-bit PowerShell from C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
}
}
Confirm-64bit
$Root = "C:\tools\LocalCoderBridge"
$ProjRoot = "C:\tools\MilkaProjects"
$PyVenv = Join-Path $Root ".venv"
$Port = 8765
New-Item -ItemType Directory -Force -Path $Root | Out-Null
New-Item -ItemType Directory -Force -Path $ProjRoot | Out-Null
# --- .env ---
@"
PROJECT_ROOT=$ProjRoot
ALLOW_SHELL=true
PORT=$Port
"@ | Set-Content -Encoding UTF8 (Join-Path $Root ".env")
# --- requirements.txt ---
@"
fastapi
uvicorn[standard]
pydantic
python-dotenv
pyyaml
requests
"@ | Set-Content -Encoding UTF8 (Join-Path $Root "requirements.txt")
# --- bridge_server.py ---
@'
import os, subprocess, shlex, json
from pathlib import Path
from typing import List, Literal, Optional, Dict, Any
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
from dotenv import load_dotenv
import requests
load_dotenv()
PROJECT_ROOT = Path(os.getenv("PROJECT_ROOT", r"C:\tools\MilkaProjects")).resolve()
ALLOW_SHELL = os.getenv("ALLOW_SHELL", "false").lower() == "true"
PORT = int(os.getenv("PORT", "8765"))
app = FastAPI(title="Local Coder Bridge", version="1.0")
# ---------- SAFETY ----------
WHITELIST_CMDS = {
"pip": ["python", "pip", "py", "python.exe"],
"python": ["python", "py", "python.exe"],
"git": ["git", "git.exe"],
"node": ["node", "npm", "npx"],
"ffmpeg": ["ffmpeg", "ffmpeg.exe"]
}
def safe_join(rel_path: str) -> Path:
p = (PROJECT_ROOT / rel_path).resolve()
if PROJECT_ROOT not in p.parents and p != PROJECT_ROOT:
raise HTTPException(400, f"path escapes PROJECT_ROOT: {p}")
return p
# ---------- SCHEMA ----------
class WriteFile(BaseModel):
action: Literal["write_file"]
path: str
content: str
encoding: Literal["utf-8","ascii"] = "utf-8"
overwrite: bool = True
class Mkdir(BaseModel):
action: Literal["mkdir"]
path: str
exist_ok: bool = True
class RunShell(BaseModel):
action: Literal["run_shell"]
command: str
cwd: Optional[str] = None
timeout_sec: int = 600
allow: Optional[List[str]] = None # allowed prefixes from WHITELIST_CMDS
class Download(BaseModel):
action: Literal["download"]
url: str
dest: str
class Task(BaseModel):
task_name: str
approve: bool = True
steps: List[Dict[str, Any]] = Field(..., description="List of action dicts conforming to schemas above")
# ---------- ACTIONS ----------
def do_write_file(step: WriteFile):
fp = safe_join(step.path)
fp.parent.mkdir(parents=True, exist_ok=True)
if fp.exists() and not step.overwrite:
return {"status":"skipped","reason":"exists and overwrite=False","path":str(fp)}
fp.write_text(step.content, encoding=step.encoding)
return {"status":"ok","path":str(fp),"bytes":len(step.content.encode(step.encoding))}
def do_mkdir(step: Mkdir):
dp = safe_join(step.path)
dp.mkdir(parents=True, exist_ok=step.exist_ok)
return {"status":"ok","path":str(dp)}
def do_download(step: Download):
dest = safe_join(step.dest)
dest.parent.mkdir(parents=True, exist_ok=True)
r = requests.get(step.url, timeout=60)
r.raise_for_status()
dest.write_bytes(r.content)
return {"status":"ok","path":str(dest),"bytes":len(r.content)}
def do_run_shell(step: RunShell):
if not ALLOW_SHELL:
return {"status":"blocked","reason":"ALLOW_SHELL=false"}
allowed = set()
if step.allow:
for k in step.allow:
allowed.update(WHITELIST_CMDS.get(k, []))
else:
for lst in WHITELIST_CMDS.values():
allowed.update(lst)
cmd_tokens = shlex.split(step.command, posix=False)
if not cmd_tokens:
raise HTTPException(400, "empty command")
# Require first token to match allowed list
first = cmd_tokens[0].lower()
if not any(first.endswith(a.lower()) or first == a.lower() for a in allowed):
raise HTTPException(400, f"command not allowed: {cmd_tokens[0]}")
cwd = safe_join(step.cwd).as_posix() if step.cwd else PROJECT_ROOT.as_posix()
try:
p = subprocess.run(cmd_tokens, cwd=cwd, capture_output=True, text=True, timeout=step.timeout_sec, shell=False)
return {
"status":"ok" if p.returncode==0 else "error",
"returncode": p.returncode,
"stdout": p.stdout[-4000:],
"stderr": p.stderr[-4000:],
"cwd": cwd,
"exec": cmd_tokens
}
except subprocess.TimeoutExpired:
return {"status":"timeout","timeout_sec":step.timeout_sec,"cmd":cmd_tokens}
# ---------- API ----------
@app.post("/run")
def run_task(task: Task):
results = []
for raw in task.steps:
action = raw.get("action")
try:
if action == "write_file":
results.append(do_write_file(WriteFile(**raw)))
elif action == "mkdir":
results.append(do_mkdir(Mkdir(**raw)))
elif action == "download":
results.append(do_download(Download(**raw)))
elif action == "run_shell":
results.append(do_run_shell(RunShell(**raw)))
else:
raise HTTPException(400, f"unknown action: {action}")
except HTTPException as e:
results.append({"status":"failed","action":action,"error":str(e.detail)})
except Exception as e:
results.append({"status":"failed","action":action,"error":repr(e)})
return {"task": task.task_name, "root": str(PROJECT_ROOT), "results": results}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=PORT)
'@ | Set-Content -Encoding UTF8 (Join-Path $Root "bridge_server.py")
# --- send_task.ps1 ---
@'
param(
[string]$Json = "",
[string]$File = "",
[string]$Url = "http://127.0.0.1:8765/run"
)
if ($File -ne "") {
$Json = Get-Content -Raw -Encoding UTF8 $File
}
if ([string]::IsNullOrWhiteSpace($Json)) {
Write-Host "Paste task JSON then press Enter twice (empty line to finish):"
$lines = @()
while ($true) {
$line = Read-Host
if ([string]::IsNullOrWhiteSpace($line)) { break }
$lines += $line
}
$Json = ($lines -join "`n")
}
try {
$resp = Invoke-RestMethod -Method Post -Uri $Url -Body $Json -ContentType "application/json; charset=utf-8"
$resp | ConvertTo-Json -Depth 8
} catch {
Write-Error $_.Exception.Message
}
'@ | Set-Content -Encoding UTF8 (Join-Path $Root "send_task.ps1")
# --- run_bridge.ps1 ---
@"
`$ErrorActionPreference = 'Stop'
Set-Location '$Root'
.\.venv\Scripts\Activate.ps1
python .\bridge_server.py
"@ | Set-Content -Encoding UTF8 (Join-Path $Root "run_bridge.ps1")
# --- optional autostart script ---
@"
# Creates a Scheduled Task to start Local Coder Bridge at user logon.
`$taskName = 'LocalCoderBridge'
`$action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File ""$Root\run_bridge.ps1"""
`$trigger = New-ScheduledTaskTrigger -AtLogOn
Register-ScheduledTask -TaskName `$taskName -Action `$action -Trigger `$trigger -Description 'Starts Local Coder Bridge at logon' -Force
"@ | Set-Content -Encoding UTF8 (Join-Path $Root "enable_autostart.ps1")
# --- sample task JSON ---
@'
{
"task_name": "hello-world",
"approve": true,
"steps": [
{ "action": "mkdir", "path": "HelloWorld", "exist_ok": true },
{ "action": "write_file", "path": "HelloWorld/hello.txt", "content": "It works.\n", "overwrite": true }
]
}
'@ | Set-Content -Encoding UTF8 (Join-Path $Root "task_sample.json")
Write-Host "Creating Python venv and installing dependencies…"
# Create venv
if (-not (Test-Path $PyVenv)) {
python -m venv $PyVenv
}
& "$PyVenv\Scripts\Activate.ps1"
python -m pip install --upgrade pip
python -m pip install -r (Join-Path $Root "requirements.txt")
# Optionally add firewall rule
try {
New-NetFirewallRule -DisplayName "LocalCoderBridge $Port" -Direction Inbound -Protocol TCP -LocalPort $Port -Action Allow -Profile Private -ErrorAction SilentlyContinue | Out-Null
} catch {}
Write-Host ""
Write-Host "----------------------------------------------"
Write-Host "Setup complete."
Write-Host "Root: $Root"
Write-Host "Project root (safe sandbox): $ProjRoot"
Write-Host "Run server: $Root\run_bridge.ps1"
Write-Host "Send a task: $Root\send_task.ps1 -File $Root\task_sample.json"
Write-Host "Optional autostart: powershell -File $Root\enable_autostart.ps1"
Write-Host "Endpoint: http://127.0.0.1:$Port/run"
Write-Host "----------------------------------------------"
Step 2 — Start the Bridge
C:\tools\LocalCoderBridge\run_bridge.ps1
Leave this window open (or use the autostart script to run it at logon, hidden).
Step 3 — Send a task (no typing, just paste)
Example using the included sample:
C:\tools\LocalCoderBridge\send_task.ps1 -File C:\tools\LocalCoderBridge\task_sample.json
Or interactive paste:
C:\tools\LocalCoderBridge\send_task.ps1
# paste JSON, press Enter twice
Ready-made Task JSON: Scaffold the Scene Prompt Factory repo
Copy this JSON and send it with send_task.ps1. It creates a repo skeleton under C:\tools\MilkaProjects\milka-scene-factory\… with starter files.
{
"task_name": "scaffold-scene-factory",
"approve": true,
"steps": [
{ "action": "mkdir", "path": "milka-scene-factory/src", "exist_ok": true },
{ "action": "mkdir", "path": "milka-scene-factory/out/.keep", "exist_ok": true },
{ "action": "write_file", "path": "milka-scene-factory/.env", "content": "OPENAI_API_KEY=PUT_YOUR_KEY_HERE\n", "overwrite": true },
{ "action": "write_file", "path": "milka-scene-factory/requirements.txt", "content": "pydantic\npython-dotenv\nrequests\ntenacity\n", "overwrite": true },
{ "action": "write_file", "path": "milka-scene-factory/README.md", "content": "# Milka Scene Prompt Factory\nRun: python src/script_to_prompts.py --in examples/script_sample.txt --out out\n", "overwrite": true },
{ "action": "write_file", "path": "milka-scene-factory/examples/script_sample.txt", "content": "SCENE: Nana & Rue balcony\nNana and Rue narrate while Tulio lights candles in Dublin.\n\nSCENE: Support Group\nDr. Carter and group react as Tulio denies the dog is his.\\n", "overwrite": true },
{ "action": "write_file", "path": "milka-scene-factory/src/models.py", "content": "from pydantic import BaseModel, Field\nfrom typing import List, Dict, Literal, Optional\n\nclass PuppetNotes(BaseModel):\n felt_texture: bool = True\n visible_rods: bool = True\n mouth_type: Literal['can-mouth'] = 'can-mouth'\n framing: str = 'knee-up white background for plates'\n\nclass Beat(BaseModel):\n line_ids: List[str] = []\n summary: str\n characters_present: List[str]\n emotions: Dict[str, List[str]] = {}\n actions: List[str] = []\n music_or_song: Optional[str] = None\n props: List[str] = []\n wardrobe_hints: Dict[str, str] = {}\n puppet_notes: PuppetNotes = PuppetNotes()\n\nclass Location(BaseModel):\n name: str\n type: Literal['interior','exterior','unknown'] = 'unknown'\n time_of_day: str = 'unknown'\n\nclass Deliverables(BaseModel):\n reference_sheet: List[str] = []\n expressions: List[str] = ['closed','open','scrunch','smile','happy','sad','angry','surprised']\n storyboard_frames: int = 6\n\nclass Scene(BaseModel):\n scene_id: str\n title: str\n location: Location\n beats: List[Beat]\n shot_direction: List[str] = []\n deliverables: Deliverables = Deliverables()\n source_refs: List[str] = []\n", "overwrite": true },
{ "action": "write_file", "path": "milka-scene-factory/src/prompt_templates.py", "content": "MASTER_SYSTEM = \"\"\"You are a script breakdown agent for a puppet-musical film. Output only what is grounded in the input text. Mark uncertainties as 'Needs verification'. Keep outputs machine-usable and consistent with the project visual bible.\"\"\"\n\nMASTER_USER_FMT = \"\"\"\nTASK\nFrom the SCRIPT below:\n1) Split into scenes.\n2) For each scene, build a canonical JSON object (schema provided).\n3) Ensure each scene includes: characters present, location, actions, per-character emotions, props, wardrobe hints, puppet notes (felt, visible rods, can-mouth, knee-up on white), shot_direction, deliverables.\n\nGLOBAL VISUAL BIBLE\n- Felt puppets, visible control rods, classic can-mouth.\n- Knee-up framing for character plates on white.\n- Distinct skin/hair tones (Nana darker grey hair, Brazilian granny; Rue Indian, softer flowing hair).\n- Expression set per character: [closed, open, scrunch, smile, happy, sad, angry, surprised].\n\nSCHEMA\n{schema}\n\nSCRIPT\n{script}\n\nOUTPUT\nReturn ONLY the JSON array. Do not wrap with prose. If any field is unknown, set \"Needs verification\".\n\"\"\"\n\nCOSTUME_TPL = \"\"\"Generate costume notes for: {characters}\nContext: {title} @ {location}\nStyle: puppet felt world; readable silhouettes; age-appropriate; nation-coded hair/skin tones.\nOutput bullets only:\n- [Char]: key garments, palette, textures, accessories\n- Group cohesion\n- Continuity flags\n\"\"\"\n\nSCENIC_TPL = \"\"\"Design the set for: {location} ({loctype}, {tod})\nInclude: background dressing, prop clusters, signage, color palette, lighting mood.\nKeep space puppet-friendly (simple planes, readable depth).\nHero props: {props}\n\"\"\"\n\nBLOCKING_TPL = \"\"\"Shot list (5–8 frames) for {title}.\nFor each: shot size, angle, who’s visible, action cue, emotion cue, camera note (pan/tilt/hold), caption ref.\nEnd with 'Continuity must-haves'.\n\"\"\"\n\nEXPRESSIONS_TPL = \"\"\"For each character in this scene, produce 9 plate prompts:\n- reference_front (knee-up on white)\n- closed, open, scrunch, smile, happy, sad, angry, surprised\nKeep: felt texture, can-mouth, rods visible, same lighting/background.\n\"\"\"\n\nCHAR_PLATE_TPL = \"\"\"Create {char} as a felt puppet: visible rods, classic can-mouth, knee-up, white background.\nKeep hair/skin rules: {rules}\nDeliver 9 images: reference_front + 8 expressions.\n\"\"\"\n", "overwrite": true },
{ "action": "write_file", "path": "milka-scene-factory/src/providers_openai_stub.txt", "content": "Placeholder: your coder will implement OpenAI/Ollama/LM Studio providers.\n", "overwrite": true }
]
}
Send it:
C:\tools\LocalCoderBridge\send_task.ps1 -File C:\tools\LocalCoderBridge\scaffold.json
# or paste it interactively with: C:\tools\LocalCoderBridge\send_task.ps1
How you’ll use it from now on
Keep run_bridge.ps1 running (or enable autostart).
When you ask me “do X,” I’ll reply with a Task JSON.
You paste it into send_task.ps1. It executes and prints results.
All files go to your sandbox: C:\tools\MilkaProjects\....
If you want me to generate the next Task JSON to fill in the OpenAI provider, CLI, and full pipeline for scene splitting and prompt pack generation, say “next task” and I’ll output it in the Task JSON format ready to paste.
You said:
from step 2 cant u do all in one script?
ChatGPT said:
Thought for 15s
Yes—let’s collapse everything into one PowerShell file that does it all in one go:
Checks 64-bit PowerShell
Creates folders
Creates virtualenv
Installs Python deps
Writes the bridge server (FastAPI), the sender tool, and helper scripts
Starts the server
Immediately sends a sample scaffold task so you can see files appear without doing anything else
Copy the script below into a new file named ALL_IN_ONE_LocalCoderBridge.ps1, then run it in 64-bit PowerShell (Admin recommended):
# ALL_IN_ONE_LocalCoderBridge.ps1
# One-shot setup: creates & runs the Local Coder Bridge, then executes a demo scaffold task.
$ErrorActionPreference = "Stop"
# --- 0) Preconditions ---
if (-not [Environment]::Is64BitProcess) {
Write-Error "This PowerShell is 32-bit. Open the 64-bit PowerShell from C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
}
# --- 1) Paths & config ---
$BridgeRoot = "C:\tools\LocalCoderBridge"
$ProjectRoot = "C:\tools\MilkaProjects"
$Port = 8765
$Venv = Join-Path $BridgeRoot ".venv"
New-Item -ItemType Directory -Force -Path $BridgeRoot | Out-Null
New-Item -ItemType Directory -Force -Path $ProjectRoot | Out-Null
# --- 2) Files: .env, requirements, server, sender, runner ---
@"
PROJECT_ROOT=$ProjectRoot
ALLOW_SHELL=true
PORT=$Port
"@ | Set-Content -Encoding UTF8 (Join-Path $BridgeRoot ".env")
@"
fastapi
uvicorn[standard]
pydantic
python-dotenv
pyyaml
requests
"@ | Set-Content -Encoding UTF8 (Join-Path $BridgeRoot "requirements.txt")
# bridge_server.py
@'
import os, subprocess, shlex
from pathlib import Path
from typing import List, Literal, Optional, Dict, Any
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
from dotenv import load_dotenv
import requests
load_dotenv()
PROJECT_ROOT = Path(os.getenv("PROJECT_ROOT", r"C:\tools\MilkaProjects")).resolve()
ALLOW_SHELL = os.getenv("ALLOW_SHELL", "false").lower() == "true"
PORT = int(os.getenv("PORT", "8765"))
app = FastAPI(title="Local Coder Bridge", version="1.0")
# SAFETY
WHITELIST_CMDS = {
"pip": ["python", "pip", "py", "python.exe"],
"python": ["python", "py", "python.exe"],
"git": ["git", "git.exe"],
"node": ["node", "npm", "npx"],
"ffmpeg": ["ffmpeg", "ffmpeg.exe"]
}
def safe_join(rel_path: str) -> Path:
p = (PROJECT_ROOT / rel_path).resolve()
if PROJECT_ROOT not in p.parents and p != PROJECT_ROOT:
raise HTTPException(400, f"path escapes PROJECT_ROOT: {p}")
return p
# SCHEMA
class WriteFile(BaseModel):
action: Literal["write_file"]
path: str
content: str
encoding: Literal["utf-8","ascii"] = "utf-8"
overwrite: bool = True
class Mkdir(BaseModel):
action: Literal["mkdir"]
path: str
exist_ok: bool = True
class RunShell(BaseModel):
action: Literal["run_shell"]
command: str
cwd: Optional[str] = None
timeout_sec: int = 600
allow: Optional[List[str]] = None
class Download(BaseModel):
action: Literal["download"]
url: str
dest: str
class Task(BaseModel):
task_name: str
approve: bool = True
steps: List[Dict[str, Any]] = Field(...)
# ACTIONS
def do_write_file(step: WriteFile):
fp = safe_join(step.path)
fp.parent.mkdir(parents=True, exist_ok=True)
if fp.exists() and not step.overwrite:
return {"status":"skipped","reason":"exists and overwrite=False","path":str(fp)}
fp.write_text(step.content, encoding=step.encoding)
return {"status":"ok","path":str(fp),"bytes":len(step.content.encode(step.encoding))}
def do_mkdir(step: Mkdir):
dp = safe_join(step.path)
dp.mkdir(parents=True, exist_ok=step.exist_ok)
return {"status":"ok","path":str(dp)}
def do_download(step: Download):
dest = safe_join(step.dest)
dest.parent.mkdir(parents=True, exist_ok=True)
r = requests.get(step.url, timeout=60)
r.raise_for_status()
dest.write_bytes(r.content)
return {"status":"ok","path":str(dest),"bytes":len(r.content)}
def do_run_shell(step: RunShell):
if not ALLOW_SHELL:
return {"status":"blocked","reason":"ALLOW_SHELL=false"}
allowed = set()
if step.allow:
for k in step.allow:
allowed.update(WHITELIST_CMDS.get(k, []))
else:
for lst in WHITELIST_CMDS.values():
allowed.update(lst)
import shlex
cmd_tokens = shlex.split(step.command, posix=False)
if not cmd_tokens:
raise HTTPException(400, "empty command")
first = cmd_tokens[0].lower()
if not any(first.endswith(a.lower()) or first == a.lower() for a in allowed):
raise HTTPException(400, f"command not allowed: {cmd_tokens[0]}")
cwd = safe_join(step.cwd).as_posix() if step.cwd else PROJECT_ROOT.as_posix()
try:
p = subprocess.run(cmd_tokens, cwd=cwd, capture_output=True, text=True, timeout=step.timeout_sec, shell=False)
return {
"status":"ok" if p.returncode==0 else "error",
"returncode": p.returncode,
"stdout": p.stdout[-4000:],
"stderr": p.stderr[-4000:],
"cwd": cwd,
"exec": cmd_tokens
}
except subprocess.TimeoutExpired:
return {"status":"timeout","timeout_sec":step.timeout_sec,"cmd":cmd_tokens}
# API
@app.post("/run")
def run_task(task: Task):
results = []
for raw in task.steps:
action = raw.get("action")
try:
if action == "write_file":
results.append(do_write_file(WriteFile(**raw)))
elif action == "mkdir":
results.append(do_mkdir(Mkdir(**raw)))
elif action == "download":
results.append(do_download(Download(**raw)))
elif action == "run_shell":
results.append(do_run_shell(RunShell(**raw)))
else:
raise HTTPException(400, f"unknown action: {action}")
except HTTPException as e:
results.append({"status":"failed","action":action,"error":str(e.detail)})
except Exception as e:
results.append({"status":"failed","action":action,"error":repr(e)})
return {"task": task.task_name, "root": str(PROJECT_ROOT), "results": results}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=PORT)
'@ | Set-Content -Encoding UTF8 (Join-Path $BridgeRoot "bridge_server.py")
# send_task.ps1
@'
param(
[string]$Json = "",
[string]$File = "",
[string]$Url = "http://127.0.0.1:8765/run"
)
if ($File -ne "") {
$Json = Get-Content -Raw -Encoding UTF8 $File
}
if ([string]::IsNullOrWhiteSpace($Json)) {
Write-Host "Paste task JSON then press Enter twice (empty line to finish):"
$lines = @()
while ($true) {
$line = Read-Host
if ([string]::IsNullOrWhiteSpace($line)) { break }
$lines += $line
}
$Json = ($lines -join "`n")
}
try {
$resp = Invoke-RestMethod -Method Post -Uri $Url -Body $Json -ContentType "application/json; charset=utf-8"
$resp | ConvertTo-Json -Depth 8
} catch {
Write-Error $_.Exception.Message
}
'@ | Set-Content -Encoding UTF8 (Join-Path $BridgeRoot "send_task.ps1")
# run_bridge.ps1
@"
`$ErrorActionPreference = 'Stop'
Set-Location '$BridgeRoot'
.\.venv\Scripts\Activate.ps1
python .\bridge_server.py
"@ | Set-Content -Encoding UTF8 (Join-Path $BridgeRoot "run_bridge.ps1")
# optional autostart
@"
`$taskName = 'LocalCoderBridge'
`$action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File ""$BridgeRoot\run_bridge.ps1"""
`$trigger = New-ScheduledTaskTrigger -AtLogOn
Register-ScheduledTask -TaskName `$taskName -Action `$action -Trigger `$trigger -Description 'Starts Local Coder Bridge at logon' -Force
"@ | Set-Content -Encoding UTF8 (Join-Path $BridgeRoot "enable_autostart.ps1")
# --- 3) Python venv + deps ---
Write-Host "Creating Python venv and installing dependencies…"
if (-not (Test-Path $Venv)) {
python -m venv $Venv
}
& "$Venv\Scripts\Activate.ps1"
python -m pip install --upgrade pip
python -m pip install -r (Join-Path $BridgeRoot "requirements.txt") | Out-Null
# Firewall allow (private)
try {
New-NetFirewallRule -DisplayName "LocalCoderBridge $Port" -Direction Inbound -Protocol TCP -LocalPort $Port -Action Allow -Profile Private -ErrorAction SilentlyContinue | Out-Null
} catch {}
# --- 4) Start server (background) ---
Write-Host "Starting Local Coder Bridge on 127.0.0.1:$Port …"
$job = Start-Job -ScriptBlock {
Param($BridgeRoot)
Set-Location $BridgeRoot
.\.venv\Scripts\Activate.ps1
python .\bridge_server.py
} -ArgumentList $BridgeRoot
Start-Sleep -Seconds 2
# --- 5) Demo scaffold task (auto-run) ---
$ScaffoldJson = @'
{
"task_name": "scaffold-scene-factory",
"approve": true,
"steps": [
{ "action": "mkdir", "path": "milka-scene-factory/src", "exist_ok": true },
{ "action": "mkdir", "path": "milka-scene-factory/out/.keep", "exist_ok": true },
{ "action": "write_file", "path": "milka-scene-factory/.env", "content": "OPENAI_API_KEY=PUT_YOUR_KEY_HERE\n", "overwrite": true },
{ "action": "write_file", "path": "milka-scene-factory/requirements.txt", "content": "pydantic\npython-dotenv\nrequests\ntenacity\n", "overwrite": true },
{ "action": "write_file", "path": "milka-scene-factory/README.md", "content": "# Milka Scene Prompt Factory\nRun: python src/script_to_prompts.py --in examples/script_sample.txt --out out\n", "overwrite": true },
{ "action": "write_file", "path": "milka-scene-factory/examples/script_sample.txt", "content": "SCENE: Nana & Rue balcony\nNana and Rue narrate while Tulio lights candles in Dublin.\n\nSCENE: Support Group\nDr. Carter and group react as Tulio denies the dog is his.\n", "overwrite": true },
{ "action": "write_file", "path": "milka-scene-factory/src/models.py", "content": "from pydantic import BaseModel\nfrom typing import List, Dict, Literal, Optional\n\nclass PuppetNotes(BaseModel):\n felt_texture: bool = True\n visible_rods: bool = True\n mouth_type: Literal['can-mouth'] = 'can-mouth'\n framing: str = 'knee-up white background for plates'\n\nclass Beat(BaseModel):\n line_ids: List[str] = []\n summary: str\n characters_present: List[str]\n emotions: Dict[str, List[str]] = {}\n actions: List[str] = []\n music_or_song: Optional[str] = None\n props: List[str] = []\n wardrobe_hints: Dict[str, str] = {}\n puppet_notes: PuppetNotes = PuppetNotes()\n\nclass Location(BaseModel):\n name: str\n type: Literal['interior','exterior','unknown'] = 'unknown'\n time_of_day: str = 'unknown'\n\nclass Deliverables(BaseModel):\n reference_sheet: List[str] = []\n expressions: List[str] = ['closed','open','scrunch','smile','happy','sad','angry','surprised']\n storyboard_frames: int = 6\n\nclass Scene(BaseModel):\n scene_id: str\n title: str\n location: Location\n beats: List[Beat]\n shot_direction: List[str] = []\n deliverables: Deliverables = Deliverables()\n source_refs: List[str] = []\n", "overwrite": true },
{ "action": "write_file", "path": "milka-scene-factory/src/prompt_templates.py", "content": "MASTER_SYSTEM = \"\"\"You are a script breakdown agent for a puppet-musical film. Output only what is grounded in the input text. Mark uncertainties as 'Needs verification'. Keep outputs machine-usable and consistent with the project visual bible.\"\"\"\n\nMASTER_USER_FMT = \"\"\"\nTASK\nFrom the SCRIPT below:\n1) Split into scenes.\n2) For each scene, build a canonical JSON object (schema provided).\n3) Ensure each scene includes: characters present, location, actions, per-character emotions, props, wardrobe hints, puppet notes (felt, visible rods, can-mouth, knee-up on white), shot_direction, deliverables.\n\nGLOBAL VISUAL BIBLE\n- Felt puppets, visible control rods, classic can-mouth.\n- Knee-up framing for character plates on white.\n- Distinct skin/hair tones (Nana darker grey hair, Brazilian granny; Rue Indian, softer flowing hair).\n- Expression set per character: [closed, open, scrunch, smile, happy, sad, angry, surprised].\n\nSCHEMA\n{schema}\n\nSCRIPT\n{script}\n\nOUTPUT\nReturn ONLY the JSON array. Do not wrap with prose. If any field is unknown, set \"Needs verification\".\n\"\"\"\n\nCOSTUME_TPL = \"\"\"Generate costume notes for: {characters}\nContext: {title} @ {location}\nStyle: puppet felt world; readable silhouettes; age-appropriate; nation-coded hair/skin tones.\nOutput bullets only:\n- [Char]: key garments, palette, textures, accessories\n- Group cohesion\n- Continuity flags\n\"\"\"\n\nSCENIC_TPL = \"\"\"Design the set for: {location} ({loctype}, {tod})\nInclude: background dressing, prop clusters, signage, color palette, lighting mood.\nKeep space puppet-friendly (simple planes, readable depth).\nHero props: {props}\n\"\"\"\n\nBLOCKING_TPL = \"\"\"Shot list (5–8 frames) for {title}.\nFor each: shot size, angle, who’s visible, action cue, emotion cue, camera note (pan/tilt/hold), caption ref.\nEnd with 'Continuity must-haves'.\n\"\"\"\n\nEXPRESSIONS_TPL = \"\"\"For each character in this scene, produce 9 plate prompts:\n- reference_front (knee-up on white)\n- closed, open, scrunch, smile, happy, sad, angry, surprised\nKeep: felt texture, can-mouth, rods visible, same lighting/background.\n\"\"\"\n\nCHAR_PLATE_TPL = \"\"\"Create {char} as a felt puppet: visible rods, classic can-mouth, knee-up, white background.\nKeep hair/skin rules: {rules}\nDeliver 9 images: reference_front + 8 expressions.\n\"\"\"\n", "overwrite": true }
]
}
'@
$ScaffoldPath = Join-Path $BridgeRoot "scaffold.json"
$ScaffoldJson | Set-Content -Encoding UTF8 $ScaffoldPath
# Send scaffold task
$Sender = Join-Path $BridgeRoot "send_task.ps1"
Write-Host "Sending scaffold task…"
& $Sender -File $ScaffoldPath | Out-Host
Write-Host ""
Write-Host "==============================================="
Write-Host "Local Coder Bridge is running."
Write-Host "Sandbox root: $ProjectRoot"
Write-Host "Server endpoint: http://127.0.0.1:$Port/run"
Write-Host "Send tasks with: $Sender (paste JSON) OR -File path.json"
Write-Host "Repo scaffold created under: $ProjectRoot\milka-scene-factory"
Write-Host "Start server later with: $BridgeRoot\run_bridge.ps1"
Write-Host "Enable autostart (optional): powershell -File $BridgeRoot\enable_autostart.ps1"
Write-Host "==============================================="
How to run
Open 64-bit PowerShell (Admin recommended).
Navigate to where you saved ALL_IN_ONE_LocalCoderBridge.ps1.
Run:
Set-ExecutionPolicy Bypass -Scope Process -Force
.\ALL_IN_ONE_LocalCoderBridge.ps1
It will:
Start the server in the background
Create C:\tools\MilkaProjects\milka-scene-factory\… with initial files
Print the endpoint and usage
What you do next
Whenever you want me to “just do it,” I’ll reply with a Task JSON.
You run:
C:\tools\LocalCoderBridge\send_task.ps1
Paste the JSON, press Enter twice. Done.
Troubleshooting
If it says you’re in 32-bit PowerShell, open the 64-bit one from C:\Windows\System32\....
If port blocked, rerun script; it adds a Private firewall rule.
If Python not found, install Python 3.11+ and reopen PowerShell.
If you want the next step (a Task JSON that fills in the OpenAI provider + CLI + end-to-end scene splitter), say “next task” and I’ll output it ready to paste into send_task.ps1.