feat: [kit] Add Forge for Freelance Services Agreement & Invoice Generation [mission-possible] .#152
Conversation
…signature placement
WalkthroughThe PR introduces Forge, a complete Next.js/Lamatic kit automating cross-border freelance contract and invoice generation. It spans a 4-step guided wizard (project details → AI pricing → governing-law tradeoff → document generation), session-based state persistence, API integration for flow execution, and document preview/signature/export functionality. ChangesForge Kit – AI-Powered Cross-Border Contract & Invoice Wizard
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Adds a new Forge kit to AgentKit: a 4-step Lamatic + Next.js wizard that collects project details, runs pricing + governing-law analysis, and generates a services agreement and invoice with signature + export UI.
Changes:
- Added 4 Lamatic flow definitions (pricing, tradeoff, contract, invoice) with prompts, constitutions, and model-config placeholders.
- Added a Next.js (App Router) frontend implementing the 4-step wizard, previews, signature capture, and export.
- Added kit metadata/docs (
lamatic.config.ts,agent.md,README.md) and local env scaffolding.
Reviewed changes
Copilot reviewed 54 out of 58 changed files in this pull request and generated 23 comments.
Show a summary per file
| File | Description |
|---|---|
| kits/forge/prompts/forge-tradeoff_llmnode-tradeoff_user_1.md | Tradeoff flow user prompt template. |
| kits/forge/prompts/forge-tradeoff_llmnode-tradeoff_system_0.md | Tradeoff flow system prompt + JSON output constraints. |
| kits/forge/prompts/forge-pricing_llmnode-pricing_user_1.md | Pricing flow user prompt template. |
| kits/forge/prompts/forge-pricing_llmnode-pricing_system_0.md | Pricing flow system prompt + JSON schema expectations. |
| kits/forge/prompts/forge-invoice_llmnode-invoice_user_1.md | Invoice flow user prompt template. |
| kits/forge/prompts/forge-invoice_llmnode-invoice_system_0.md | Invoice flow system prompt + strict JSON rules. |
| kits/forge/prompts/forge-contract_llmnode-contract_user_1.md | Contract flow user prompt template. |
| kits/forge/prompts/forge-contract_llmnode-contract_system_0.md | Contract flow system prompt describing 13-section contract JSON output. |
| kits/forge/model-configs/forge-tradeoff_llmnode-tradeoff_generative-model-name.ts | Placeholder model-config for tradeoff LLM node. |
| kits/forge/model-configs/forge-pricing_llmnode-pricing_generative-model-name.ts | Placeholder model-config for pricing LLM node. |
| kits/forge/model-configs/forge-invoice_llmnode-invoice_generative-model-name.ts | Placeholder model-config for invoice LLM node. |
| kits/forge/model-configs/forge-contract_llmnode-contract_generative-model-name.ts | Placeholder model-config for contract LLM node. |
| kits/forge/lamatic.config.ts | Kit metadata (name/steps/env keys/links). |
| kits/forge/flows/forge-tradeoff.ts | Lamatic flow graph for governing-law options. |
| kits/forge/flows/forge-pricing.ts | Lamatic flow graph for pricing analysis. |
| kits/forge/flows/forge-invoice.ts | Lamatic flow graph for invoice generation. |
| kits/forge/flows/forge-contract.ts | Lamatic flow graph for contract generation. |
| kits/forge/constitutions/default.md | Kit constitution/guardrails for agent behavior. |
| kits/forge/apps/tsconfig.json | Next.js app TS config. |
| kits/forge/apps/tailwind.config.js | Tailwind theme + content config. |
| kits/forge/apps/public/forge2.svg | App logo asset. |
| kits/forge/apps/postcss.config.js | PostCSS config for Tailwind. |
| kits/forge/apps/package.json | App dependencies/scripts. |
| kits/forge/apps/orchestrate.js | Centralized env-driven flow configuration. |
| kits/forge/apps/next.config.mjs | Next.js config (TS/build/image settings). |
| kits/forge/apps/lib/utils.ts | Tailwind/className helper (cn). |
| kits/forge/apps/lib/types.ts | Shared session + document data types. |
| kits/forge/apps/lib/storage.ts | localStorage session persistence helpers. |
| kits/forge/apps/lib/lamatic.ts | Client helper to call /api/flow. |
| kits/forge/apps/lib/lamatic-client.ts | Server-side Lamatic SDK client init. |
| kits/forge/apps/components/wizard/StepIndicator.tsx | Wizard step indicator UI. |
| kits/forge/apps/components/wizard/Step4Generate.tsx | Step 4: generate contract/invoice and store in session. |
| kits/forge/apps/components/wizard/Step3GoverningLaw.tsx | Step 3: call tradeoff flow + select option. |
| kits/forge/apps/components/wizard/Step2Pricing.tsx | Step 2: call pricing flow + edit line items. |
| kits/forge/apps/components/wizard/Step1ProjectDetails.tsx | Step 1: project details form persisted to session. |
| kits/forge/apps/components/preview/SignatureCanvas.tsx | Signature capture modal/canvas. |
| kits/forge/apps/components/preview/InvoiceDocument.tsx | Invoice rendering component for preview/print. |
| kits/forge/apps/components/preview/ExportButton.tsx | Export action UI (currently print-based). |
| kits/forge/apps/components/preview/ContractDocument.tsx | Contract rendering component for preview/print. |
| kits/forge/apps/components/Nav.tsx | Top navigation with logo. |
| kits/forge/apps/components/GalaxyButton.tsx | Primary CTA button component. |
| kits/forge/apps/components/ErrorState.tsx | Standard error + retry UI. |
| kits/forge/apps/components/AuroraBackground.tsx | Animated background wrapper. |
| kits/forge/apps/app/preview/invoice/page.tsx | Invoice preview page with signing/export actions. |
| kits/forge/apps/app/preview/contract/page.tsx | Contract preview page with signing/export actions. |
| kits/forge/apps/app/page.tsx | Landing page for the kit app. |
| kits/forge/apps/app/new/page.tsx | Wizard container page. |
| kits/forge/apps/app/layout.tsx | Root layout + metadata + nav. |
| kits/forge/apps/app/icon.svg | App icon asset. |
| kits/forge/apps/app/globals.css | Global styling, components, and print CSS. |
| kits/forge/apps/app/api/flow/route.ts | Server proxy route that executes Lamatic workflows via GraphQL. |
| kits/forge/apps/actions/orchestrate.ts | Server action wrapper around Lamatic SDK execution. |
| kits/forge/apps/.gitignore | App-level ignore rules. |
| kits/forge/apps/.env.example | Environment variable template. |
| kits/forge/agent.md | Kit/agent overview and operational notes. |
| kits/forge/README.md | Kit documentation: setup, flows, and usage. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 54 out of 58 changed files in this pull request and generated 16 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
/validate |
|
📡 Running Studio validation — results will appear here shortly. |
Studio Runtime Validation (Phase 2)✅ Studio validation passed. The kit loaded successfully in Lamatic Studio. This PR is ready for final review and merge. |
There was a problem hiding this comment.
Actionable comments posted: 19
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@kits/forge/apps/app/api/flow/route.ts`:
- Around line 20-23: The route currently reads client-exposed env names
(endpoint/projectId) from NEXT_PUBLIC_LAMATIC_ENDPOINT and
NEXT_PUBLIC_LAMATIC_PROJECT_ID; change it to use the server-only names
LAMATIC_API_URL and LAMATIC_PROJECT_ID and keep LAMATIC_API_KEY for the secret
so the route uses server-only credentials (update the variables endpoint ->
LAMATIC_API_URL, projectId -> LAMATIC_PROJECT_ID, and keep apiKey ->
LAMATIC_API_KEY). Also ensure these names match the initialization in
kits/**/lib/lamatic-client.ts so the Lamatic client (init code in
lamatic-client.ts) and this route use the same env variable names.
- Around line 17-19: The POST handler's call to await req.json() is unguarded
and can throw before your error-path runs; move the body parsing into the
existing try/catch (or add one) so that the destructuring const { flowId,
payload } = await req.json() happens inside the guarded block, catch JSON parse
errors and return/throw the same structured error response you use downstream
(or call the existing error handler). Update the POST function to ensure any
parsing error for req.json is logged/handled consistently with the handler's
other failures.
- Around line 50-58: The outbound fetch call in route.ts that posts graphqlQuery
to endpoint (using endpoint, apiKey, projectId) needs an AbortController and a
timeout to avoid hangs; update the POST logic that calls fetch(...) to create an
AbortController, pass controller.signal to fetch, start a timer (e.g.,
setTimeout) that calls controller.abort() after a configurable timeout, and
clear the timer when the request finishes; also catch abort/errors from fetch
and map them to an appropriate response (timeout vs other error) so the route
doesn't remain pinned waiting on the upstream.
In `@kits/forge/apps/app/globals.css`:
- Around line 4-6: globals.css currently uses Tailwind v3 layer directives
(`@tailwind` base; `@tailwind` components; `@tailwind` utilities;) while package.json
pins tailwindcss to ^3.4.1; update to Tailwind v4+ by bumping the tailwindcss
dependency in package.json to a v4+ release and migrate globals.css to the v4
CSS entry format (replace the `@tailwind` layer directives with the new v4
imports/configured CSS pattern per Tailwind v4 docs), or if you intend to stay
on v3, update the kit guidance instead; ensure you update any Tailwind-related
build/postcss config to match the v4 migration steps so the project builds
correctly.
In `@kits/forge/apps/app/preview/invoice/page.tsx`:
- Around line 19-32: The invoice number is currently generated with
useState(`INV-${Date.now()}`) causing a new number on every mount; instead, on
mount read session.invoice_number from getSession() and if present initialize
invoiceNumber from that value, otherwise generate a new ID, set
session.invoice_number to it and persist the session (via your session
persistence helper—e.g., saveSession/setSession) so subsequent mounts use the
same number; update references to invoiceNumber and where you call
setInvoice/getSession so the component uses the persisted session.invoice_number
rather than always creating `INV-${Date.now()}`.
In `@kits/forge/apps/components/AuroraBackground.tsx`:
- Around line 22-38: The effect is being torn down and rebuilt on every
mousemove because useEffect depends on mousePos; stop deriving the animation
target from state and instead store the target in a ref (e.g., create
targetPosRef and update it inside your mousemove handler instead of via
setMousePos so children aren’t re-rendered), then change the rAF loop useEffect
(the one that defines updateOrb, uses currentPos and requestRef and queries
"interactive-orb") to run once on mount (empty dependency array) and read from
targetPosRef inside updateOrb; start the rAF once (requestRef.current =
requestAnimationFrame(updateOrb)) and cancel on unmount to prevent repeated
teardown/recreate of updateOrb.
In `@kits/forge/apps/components/GalaxyButton.tsx`:
- Around line 53-116: The current ButtonContent creates a real <button> and then
nests it inside <Link>, which is invalid; refactor so the interactive element
matches the presence of href: extract the visual inner spans (the backdrop,
stars, galaxy-text, etc.) into a pure presentational fragment (e.g.,
renderInnerContent or move the JSX out of the <button> wrapper) and then
conditionally render either a <button> (when href is falsy) or a <Link> anchor
(when href is truthy) as the outer interactive element; when rendering <Link>
pass the same classNames, handle clicks via onClick, set aria-disabled or
tabIndex and apply the disabled styling instead of nesting a <button>, and keep
the existing disabled prop logic for the <button> branch (reference
ButtonContent, Link, onClick, disabled, showArrow, staticStars, orbitingStars).
In `@kits/forge/apps/components/preview/SignatureCanvas.tsx`:
- Around line 41-60: The baseline-drawing logic is duplicated in handleClear and
the mount useEffect; extract it into a single helper drawBaseline(canvas) and
call that helper from both places. Implement drawBaseline to accept the
HTMLCanvasElement (from sigRef.current?.getCanvas()), obtain its 2D context, set
strokeStyle/lineWidth/setLineDash, and draw the same guide line, then replace
the inline blocks in handleClear and the useEffect with a call to
drawBaseline(canvas); ensure sigRef and getCanvas usage remains unchanged and
guard for null canvas/context before calling the helper.
- Around line 17-66: The dashed baseline is being drawn onto the signing canvas
(in useEffect and in handleClear via
sigRef.current?.getCanvas().getContext("2d")), so it ends up baked into the PNG
produced by handleConfirm (sigRef.current?.toDataURL). Remove the two blocks
that call getContext and draw the dashed line (the entire baseline draw in
useEffect and the redraw in handleClear) and instead render the dashed baseline
as a separate layer (e.g., a CSS background or an absolutely positioned div
overlay behind/above the <SignatureCanvas/> element) so the canvas (sigRef) only
contains user strokes and handleConfirm returns a clean signature image.
In `@kits/forge/apps/components/wizard/Step1ProjectDetails.tsx`:
- Around line 52-56: handleSubmit currently calls updateSession with the entire
form (including freelancer_payment_details and emails) which ends up persisted
in localStorage; change it to avoid storing sensitive payment info and use
ephemeral sessionStorage for the wizard lifetime: before calling updateSession,
create a sanitized copy of form that omits freelancer_payment_details and any
unnecessary raw payment/email fields (retain only IDs or masked values required
later), then call updateSession with that sanitized object and ensure
updateSession is using sessionStorage (or provide a new updateEphemeralSession
helper) rather than localStorage; update references to handleSubmit,
updateSession, and form to reflect the sanitized payload.
- Around line 38-65: Step1ProjectDetails currently uses local useState (INITIAL,
set, handleSubmit) and native required attrs; replace this with react-hook-form
+ zod schema for ProjectDetails (define validation rules: email format,
non-negative numeric fields like years, and date ordering) and wire the form via
useForm and zodResolver instead of set/useState; swap plain inputs/selects with
shadcn/ui (and Radix where appropriate) form primitives and controlled
register/Controller usage so validation and UI match repo standards; ensure
submit still calls updateSession({ projectDetails: values }) and onComplete()
after valid submit and restore defaults from getSession into form's
defaultValues.
In `@kits/forge/apps/components/wizard/Step2Pricing.tsx`:
- Around line 47-49: The code assigns parsed into state without validating its
shape, so before calling setPricing verify that parsed has a line_items property
that is an array (i.e. check parsed && Array.isArray(parsed.line_items)); if it
does, call setPricing(parsed), otherwise either set a safe fallback (e.g.
setPricing({...parsed, line_items: []})) or surface the existing error handling
path (set an error state) so the subsequent pricing.line_items.map(...) in the
render cannot crash; reference: pricingRaw, parsed, setPricing, PricingResult
and the usage pricing.line_items.map to locate where to add the guard.
In `@kits/forge/apps/components/wizard/Step3GoverningLaw.tsx`:
- Around line 57-63: The code currently assumes response.result.options parses
to an array; validate that parsed is an array before using it: after computing
optionsRaw and parsed (variables named optionsRaw and parsed in
Step3GoverningLaw), check Array.isArray(parsed) and if not, route to the
existing ErrorState (do not call setOptions, findIndex, setSelected, or rely on
options.map). If it is an array, then call setOptions(parsed) and run the
auto-selection logic (use parsed.findIndex and setSelected as before). Ensure
any JSON.parse errors are also caught and handled by showing ErrorState.
In `@kits/forge/apps/lib/lamatic-client.ts`:
- Around line 9-17: The client initialization in lib/lamatic-client.ts checks
for endpoint and apiKey but doesn't validate projectId; update the
initialization in the function that assigns _client (where new Lamatic({...}) is
called) to throw an Error when config.api.projectId (LAMATIC_PROJECT_ID) is
missing or null so the process fails fast; ensure the error message clearly
names the missing LAMATIC_PROJECT_ID variable and keep the rest of the Lamatic
constructor usage unchanged.
In `@kits/forge/apps/lib/storage.ts`:
- Around line 5-18: The session helpers (getSession, updateSession,
clearSession) must be hardened against non-browser contexts and malformed
localStorage data: in getSession wrap localStorage access and JSON.parse in a
try/catch and return {} on any error; ensure you only access localStorage when
typeof window !== 'undefined' (or wrap the access itself in try/catch) to avoid
server-side crashes; in updateSession wrap the localStorage.setItem call in
try/catch, merge safely with the result of getSession (ensuring it is an object)
before stringifying, and swallow/log errors instead of throwing; in clearSession
similarly guard/removeItem in a try/catch so calls are no-ops outside a browser
or when storage is corrupted.
In `@kits/forge/apps/orchestrate.js`:
- Around line 3-4: The orchestration identifiers (endpoint, projectId, flowId)
are currently read from NEXT_PUBLIC_* env vars and thus leak to the client;
change all references that set endpoint, projectId, and any flowId values in
orchestrate.js to use server-only env vars (e.g., process.env.LAMATIC_ENDPOINT,
process.env.LAMATIC_PROJECT_ID, process.env.LAMATIC_FLOW_ID) instead of
NEXT_PUBLIC_*; ensure these values are only used in server-side code paths
(remove any exports or client-side propagation) and add a fail-fast check in the
initialization logic that throws or logs an error if the required server-only
vars are missing.
- Around line 3-5: The current config silently defaults endpoint, projectId and
apiKey to empty strings (endpoint, projectId, apiKey) which delays errors;
instead validate process.env.NEXT_PUBLIC_LAMATIC_ENDPOINT,
process.env.NEXT_PUBLIC_LAMATIC_PROJECT_ID and process.env.LAMATIC_API_KEY at
module initialization and throw a clear Error (or assert) if any are missing so
the app fails fast on startup; update the code around where
endpoint/projectId/apiKey are set to remove the "?? ''" defaults and add a small
validation block that constructs a helpful message listing the missing env var
names before throwing.
In `@kits/forge/apps/package.json`:
- Around line 13-32: Update kits/forge/apps/package.json by replacing all
non-exact dependency specifiers with exact versions: change "react",
"react-dom", "lamatic", "clsx", "tailwind-merge", "lucide-react",
"react-markdown", and "react-signature-canvas" in the "dependencies" section and
"typescript", "`@types/node`", "`@types/react`", "`@types/react-dom`",
"`@types/react-signature-canvas`", "tailwindcss", "autoprefixer", "postcss", and
"eslint" in "devDependencies" from ranges or "latest" to concrete version
strings (no ^, ~, or "latest"); keep the existing exact entries such as
"eslint-config-next" unchanged. Ensure each entry is a fixed version literal
(e.g., "18.2.0" style) and run a quick install to verify no conflicts.
In `@kits/forge/prompts/forge-invoice_llmnode-invoice_system_0.md`:
- Around line 44-45: The prompt currently contains conflicting directives for
the output schema: one line mandates a fixed keyset including "line_items" while
another allows omitting or leaving "notes" empty, which can cause schema drift;
update the prompt in forge-invoice_llmnode-invoice_system_0.md to remove the
contradictory allowance so the keys are consistent — keep "line_items: use
exactly what is provided. Do not modify amounts." and change the "notes"
instruction to a single clear rule (either "notes: include the freelancer's
notes if provided, otherwise set as empty string" OR "notes: always include the
field, empty string if not provided") so downstream parsers receive a stable
schema.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro
Run ID: a9634588-dcbc-4619-bc77-abdef8867c1f
⛔ Files ignored due to path filters (4)
kits/forge/apps/app/icon.svgis excluded by!**/*.svgkits/forge/apps/package-lock.jsonis excluded by!**/package-lock.jsonkits/forge/apps/public/forge2.svgis excluded by!**/*.svgkits/forge/apps/public/screenshot.pngis excluded by!**/*.png
📒 Files selected for processing (54)
kits/forge/README.mdkits/forge/agent.mdkits/forge/apps/.env.examplekits/forge/apps/.gitignorekits/forge/apps/actions/orchestrate.tskits/forge/apps/app/api/flow/route.tskits/forge/apps/app/globals.csskits/forge/apps/app/layout.tsxkits/forge/apps/app/new/page.tsxkits/forge/apps/app/page.tsxkits/forge/apps/app/preview/contract/page.tsxkits/forge/apps/app/preview/invoice/page.tsxkits/forge/apps/components/AuroraBackground.tsxkits/forge/apps/components/ErrorState.tsxkits/forge/apps/components/GalaxyButton.tsxkits/forge/apps/components/Nav.tsxkits/forge/apps/components/preview/ContractDocument.tsxkits/forge/apps/components/preview/ExportButton.tsxkits/forge/apps/components/preview/InvoiceDocument.tsxkits/forge/apps/components/preview/SignatureCanvas.tsxkits/forge/apps/components/wizard/Step1ProjectDetails.tsxkits/forge/apps/components/wizard/Step2Pricing.tsxkits/forge/apps/components/wizard/Step3GoverningLaw.tsxkits/forge/apps/components/wizard/Step4Generate.tsxkits/forge/apps/components/wizard/StepIndicator.tsxkits/forge/apps/lib/lamatic-client.tskits/forge/apps/lib/lamatic.tskits/forge/apps/lib/storage.tskits/forge/apps/lib/types.tskits/forge/apps/lib/utils.tskits/forge/apps/next.config.mjskits/forge/apps/orchestrate.jskits/forge/apps/package.jsonkits/forge/apps/postcss.config.jskits/forge/apps/tailwind.config.jskits/forge/apps/tsconfig.jsonkits/forge/constitutions/default.mdkits/forge/flows/forge-contract.tskits/forge/flows/forge-invoice.tskits/forge/flows/forge-pricing.tskits/forge/flows/forge-tradeoff.tskits/forge/lamatic.config.tskits/forge/model-configs/forge-contract_llmnode-contract_generative-model-name.tskits/forge/model-configs/forge-invoice_llmnode-invoice_generative-model-name.tskits/forge/model-configs/forge-pricing_llmnode-pricing_generative-model-name.tskits/forge/model-configs/forge-tradeoff_llmnode-tradeoff_generative-model-name.tskits/forge/prompts/forge-contract_llmnode-contract_system_0.mdkits/forge/prompts/forge-contract_llmnode-contract_user_1.mdkits/forge/prompts/forge-invoice_llmnode-invoice_system_0.mdkits/forge/prompts/forge-invoice_llmnode-invoice_user_1.mdkits/forge/prompts/forge-pricing_llmnode-pricing_system_0.mdkits/forge/prompts/forge-pricing_llmnode-pricing_user_1.mdkits/forge/prompts/forge-tradeoff_llmnode-tradeoff_system_0.mdkits/forge/prompts/forge-tradeoff_llmnode-tradeoff_user_1.md
| export async function POST(req: NextRequest) { | ||
| const { flowId, payload } = await req.json(); | ||
|
|
There was a problem hiding this comment.
Mission safeguard: parse request JSON inside guarded error handling.
If body parsing fails at Line 18, it bypasses your downstream error-path logic and returns an unstructured failure.
Proposed patch
export async function POST(req: NextRequest) {
- const { flowId, payload } = await req.json();
+ let flowId: unknown;
+ let payload: unknown;
+ try {
+ ({ flowId, payload } = await req.json());
+ } catch {
+ return NextResponse.json({ error: 'Invalid JSON body.' }, { status: 400 });
+ }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@kits/forge/apps/app/api/flow/route.ts` around lines 17 - 19, The POST
handler's call to await req.json() is unguarded and can throw before your
error-path runs; move the body parsing into the existing try/catch (or add one)
so that the destructuring const { flowId, payload } = await req.json() happens
inside the guarded block, catch JSON parse errors and return/throw the same
structured error response you use downstream (or call the existing error
handler). Update the POST function to ensure any parsing error for req.json is
logged/handled consistently with the handler's other failures.
| const endpoint = process.env.NEXT_PUBLIC_LAMATIC_ENDPOINT; | ||
| const projectId = process.env.NEXT_PUBLIC_LAMATIC_PROJECT_ID; | ||
| const apiKey = process.env.LAMATIC_API_KEY; | ||
|
|
There was a problem hiding this comment.
Mission directive: switch to server-only Lamatic env keys to avoid config drift.
This route depends on NEXT_PUBLIC_LAMATIC_ENDPOINT/NEXT_PUBLIC_LAMATIC_PROJECT_ID at Lines 20-21, which couples a server credential path to client-exposed naming and can break if only server-side keys are configured.
Proposed patch
- const endpoint = process.env.NEXT_PUBLIC_LAMATIC_ENDPOINT;
- const projectId = process.env.NEXT_PUBLIC_LAMATIC_PROJECT_ID;
+ const endpoint = process.env.LAMATIC_API_URL;
+ const projectId = process.env.LAMATIC_PROJECT_ID;
const apiKey = process.env.LAMATIC_API_KEY;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@kits/forge/apps/app/api/flow/route.ts` around lines 20 - 23, The route
currently reads client-exposed env names (endpoint/projectId) from
NEXT_PUBLIC_LAMATIC_ENDPOINT and NEXT_PUBLIC_LAMATIC_PROJECT_ID; change it to
use the server-only names LAMATIC_API_URL and LAMATIC_PROJECT_ID and keep
LAMATIC_API_KEY for the secret so the route uses server-only credentials (update
the variables endpoint -> LAMATIC_API_URL, projectId -> LAMATIC_PROJECT_ID, and
keep apiKey -> LAMATIC_API_KEY). Also ensure these names match the
initialization in kits/**/lib/lamatic-client.ts so the Lamatic client (init code
in lamatic-client.ts) and this route use the same env variable names.
| const res = await fetch(endpoint, { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| 'Authorization': `Bearer ${apiKey}`, | ||
| 'x-project-id': projectId, | ||
| }, | ||
| body: JSON.stringify(graphqlQuery), | ||
| }); |
There was a problem hiding this comment.
Mission resilience gap: outbound Lamatic fetch needs a timeout/abort controller.
The external call currently has no timeout. A hung upstream can pin this route until platform hard timeouts.
Proposed patch
try {
+ const controller = new AbortController();
+ const timeout = setTimeout(() => controller.abort(), 15_000);
const res = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`,
'x-project-id': projectId,
},
body: JSON.stringify(graphqlQuery),
+ signal: controller.signal,
});
+ clearTimeout(timeout);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const res = await fetch(endpoint, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| 'Authorization': `Bearer ${apiKey}`, | |
| 'x-project-id': projectId, | |
| }, | |
| body: JSON.stringify(graphqlQuery), | |
| }); | |
| const controller = new AbortController(); | |
| const timeout = setTimeout(() => controller.abort(), 15_000); | |
| const res = await fetch(endpoint, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| 'Authorization': `Bearer ${apiKey}`, | |
| 'x-project-id': projectId, | |
| }, | |
| body: JSON.stringify(graphqlQuery), | |
| signal: controller.signal, | |
| }); | |
| clearTimeout(timeout); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@kits/forge/apps/app/api/flow/route.ts` around lines 50 - 58, The outbound
fetch call in route.ts that posts graphqlQuery to endpoint (using endpoint,
apiKey, projectId) needs an AbortController and a timeout to avoid hangs; update
the POST logic that calls fetch(...) to create an AbortController, pass
controller.signal to fetch, start a timer (e.g., setTimeout) that calls
controller.abort() after a configurable timeout, and clear the timer when the
request finishes; also catch abort/errors from fetch and map them to an
appropriate response (timeout vs other error) so the route doesn't remain pinned
waiting on the upstream.
| @tailwind base; | ||
| @tailwind components; | ||
| @tailwind utilities; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm the Tailwind version pinned for the Forge kit
fd -t f 'package.json' kits/forge | while read -r f; do
echo "== $f =="
jq '{tailwind: (.dependencies.tailwindcss // .devDependencies.tailwindcss)}' "$f"
doneRepository: Lamatic/AgentKit
Length of output: 122
Mission: adjust Tailwind to match the v4+ CSS guideline
kits/forge/apps/app/globals.css uses Tailwind v3 layer directives (@tailwind base/components/utilities), and kits/forge/apps/package.json pins tailwindcss to ^3.4.1 (Tailwind v3), so the current state conflicts with the “kits/**/*.css: Use Tailwind CSS v4+” guideline. Upgrade tailwindcss to v4+ and migrate the directives to Tailwind v4’s CSS form (or, if v3 is intentional, update the guideline/intent for this kit).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@kits/forge/apps/app/globals.css` around lines 4 - 6, globals.css currently
uses Tailwind v3 layer directives (`@tailwind` base; `@tailwind` components;
`@tailwind` utilities;) while package.json pins tailwindcss to ^3.4.1; update to
Tailwind v4+ by bumping the tailwindcss dependency in package.json to a v4+
release and migrate globals.css to the v4 CSS entry format (replace the
`@tailwind` layer directives with the new v4 imports/configured CSS pattern per
Tailwind v4 docs), or if you intend to stay on v3, update the kit guidance
instead; ensure you update any Tailwind-related build/postcss config to match
the v4 migration steps so the project builds correctly.
| const [invoiceNumber] = useState(`INV-${Date.now()}`); | ||
| const [showSigModal, setShowSigModal] = useState(false); | ||
|
|
||
| useEffect(() => { | ||
| const session = getSession(); | ||
| if (!session.invoice || !session.projectDetails) { | ||
| router.push("/new"); | ||
| return; | ||
| } | ||
| setInvoice(session.invoice); | ||
| setSignature(session.invoice_signature || null); | ||
| setProjectTitle(session.projectDetails.project_title); | ||
| setCurrency(session.pricing?.currency || session.projectDetails.payment_currency || "USD"); | ||
| }, [router]); |
There was a problem hiding this comment.
Agent, this invoice number self-destructs on every reload.
INV-${Date.now()} is minted fresh on each mount and never persisted, so a refresh — or bouncing to the contract page and back — re-issues a different number for the same invoice. Two exports won't agree.
Persist it once and reuse:
🧾 Proposed fix — pin the invoice number to the session
- const [invoiceNumber] = useState(`INV-${Date.now()}`);
+ const [invoiceNumber, setInvoiceNumber] = useState("");
const [showSigModal, setShowSigModal] = useState(false);
useEffect(() => {
const session = getSession();
if (!session.invoice || !session.projectDetails) {
router.push("/new");
return;
}
+ const existing = session.invoice_number || `INV-${Date.now()}`;
+ if (!session.invoice_number) updateSession({ invoice_number: existing });
+ setInvoiceNumber(existing);
setInvoice(session.invoice);Note: this assumes invoice_number is added to the session type — confirm against lib/types.ts.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@kits/forge/apps/app/preview/invoice/page.tsx` around lines 19 - 32, The
invoice number is currently generated with useState(`INV-${Date.now()}`) causing
a new number on every mount; instead, on mount read session.invoice_number from
getSession() and if present initialize invoiceNumber from that value, otherwise
generate a new ID, set session.invoice_number to it and persist the session (via
your session persistence helper—e.g., saveSession/setSession) so subsequent
mounts use the same number; update references to invoiceNumber and where you
call setInvoice/getSession so the component uses the persisted
session.invoice_number rather than always creating `INV-${Date.now()}`.
| export function getSession(): Partial<ForgeSession> { | ||
| if (typeof window === 'undefined') return {}; | ||
| const raw = localStorage.getItem(KEY); | ||
| return raw ? JSON.parse(raw) : {}; | ||
| } | ||
|
|
||
| export function updateSession(patch: Partial<ForgeSession>) { | ||
| const current = getSession(); | ||
| localStorage.setItem(KEY, JSON.stringify({ ...current, ...patch })); | ||
| } | ||
|
|
||
| export function clearSession() { | ||
| localStorage.removeItem(KEY); | ||
| } |
There was a problem hiding this comment.
Mission-critical hardening: prevent session utilities from crashing on malformed or server-side storage access.
JSON.parse at Line 8 can throw on corrupted storage, and localStorage access at Lines 13/17 can throw if these functions are called in a non-browser context. This can brick the wizard state path unexpectedly.
Proposed patch
export function getSession(): Partial<ForgeSession> {
if (typeof window === 'undefined') return {};
const raw = localStorage.getItem(KEY);
- return raw ? JSON.parse(raw) : {};
+ if (!raw) return {};
+ try {
+ return JSON.parse(raw);
+ } catch {
+ localStorage.removeItem(KEY);
+ return {};
+ }
}
export function updateSession(patch: Partial<ForgeSession>) {
+ if (typeof window === 'undefined') return;
const current = getSession();
localStorage.setItem(KEY, JSON.stringify({ ...current, ...patch }));
}
export function clearSession() {
+ if (typeof window === 'undefined') return;
localStorage.removeItem(KEY);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export function getSession(): Partial<ForgeSession> { | |
| if (typeof window === 'undefined') return {}; | |
| const raw = localStorage.getItem(KEY); | |
| return raw ? JSON.parse(raw) : {}; | |
| } | |
| export function updateSession(patch: Partial<ForgeSession>) { | |
| const current = getSession(); | |
| localStorage.setItem(KEY, JSON.stringify({ ...current, ...patch })); | |
| } | |
| export function clearSession() { | |
| localStorage.removeItem(KEY); | |
| } | |
| export function getSession(): Partial<ForgeSession> { | |
| if (typeof window === 'undefined') return {}; | |
| const raw = localStorage.getItem(KEY); | |
| if (!raw) return {}; | |
| try { | |
| return JSON.parse(raw); | |
| } catch { | |
| localStorage.removeItem(KEY); | |
| return {}; | |
| } | |
| } | |
| export function updateSession(patch: Partial<ForgeSession>) { | |
| if (typeof window === 'undefined') return; | |
| const current = getSession(); | |
| localStorage.setItem(KEY, JSON.stringify({ ...current, ...patch })); | |
| } | |
| export function clearSession() { | |
| if (typeof window === 'undefined') return; | |
| localStorage.removeItem(KEY); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@kits/forge/apps/lib/storage.ts` around lines 5 - 18, The session helpers
(getSession, updateSession, clearSession) must be hardened against non-browser
contexts and malformed localStorage data: in getSession wrap localStorage access
and JSON.parse in a try/catch and return {} on any error; ensure you only access
localStorage when typeof window !== 'undefined' (or wrap the access itself in
try/catch) to avoid server-side crashes; in updateSession wrap the
localStorage.setItem call in try/catch, merge safely with the result of
getSession (ensuring it is an object) before stringifying, and swallow/log
errors instead of throwing; in clearSession similarly guard/removeItem in a
try/catch so calls are no-ops outside a browser or when storage is corrupted.
| endpoint: process.env.NEXT_PUBLIC_LAMATIC_ENDPOINT ?? "", | ||
| projectId: process.env.NEXT_PUBLIC_LAMATIC_PROJECT_ID ?? "", |
There was a problem hiding this comment.
Mission-critical: keep orchestration identifiers server-only.
Line 3, Line 4, Line 10, Line 25, Line 47, and Line 70 use NEXT_PUBLIC_* for Lamatic endpoint/project/flow IDs. Those values should not be exposed client-side when they control server-side flow execution.
Suggested hardening diff
export const config = {
api: {
- endpoint: process.env.NEXT_PUBLIC_LAMATIC_ENDPOINT ?? "",
- projectId: process.env.NEXT_PUBLIC_LAMATIC_PROJECT_ID ?? "",
+ endpoint: process.env.LAMATIC_API_URL ?? "",
+ projectId: process.env.LAMATIC_PROJECT_ID ?? "",
apiKey: process.env.LAMATIC_API_KEY ?? "",
},
flows: {
pricing: {
name: "Forge Pricing",
- workflowId: process.env.NEXT_PUBLIC_FLOW_PRICING ?? "",
+ workflowId: process.env.FLOW_PRICING ?? "",
@@
tradeoff: {
name: "Forge Tradeoff",
- workflowId: process.env.NEXT_PUBLIC_FLOW_TRADEOFF ?? "",
+ workflowId: process.env.FLOW_TRADEOFF ?? "",
@@
contract: {
name: "Forge Contract",
- workflowId: process.env.NEXT_PUBLIC_FLOW_CONTRACT ?? "",
+ workflowId: process.env.FLOW_CONTRACT ?? "",
@@
invoice: {
name: "Forge Invoice",
- workflowId: process.env.NEXT_PUBLIC_FLOW_INVOICE ?? "",
+ workflowId: process.env.FLOW_INVOICE ?? "",Also applies to: 10-10, 25-25, 47-47, 70-70
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@kits/forge/apps/orchestrate.js` around lines 3 - 4, The orchestration
identifiers (endpoint, projectId, flowId) are currently read from NEXT_PUBLIC_*
env vars and thus leak to the client; change all references that set endpoint,
projectId, and any flowId values in orchestrate.js to use server-only env vars
(e.g., process.env.LAMATIC_ENDPOINT, process.env.LAMATIC_PROJECT_ID,
process.env.LAMATIC_FLOW_ID) instead of NEXT_PUBLIC_*; ensure these values are
only used in server-side code paths (remove any exports or client-side
propagation) and add a fail-fast check in the initialization logic that throws
or logs an error if the required server-only vars are missing.
| endpoint: process.env.NEXT_PUBLIC_LAMATIC_ENDPOINT ?? "", | ||
| projectId: process.env.NEXT_PUBLIC_LAMATIC_PROJECT_ID ?? "", | ||
| apiKey: process.env.LAMATIC_API_KEY ?? "", |
There was a problem hiding this comment.
Mission directive: fail fast on missing env vars.
Line 3, Line 4, Line 5, Line 10, Line 25, Line 47, and Line 70 default to empty strings. That defers config errors until runtime flow calls and makes failures harder to diagnose.
Suggested fail-fast diff
+const requireEnv = (key) => {
+ const value = process.env[key]
+ if (!value) throw new Error(`Missing required env var: ${key}`)
+ return value
+}
+
export const config = {
api: {
- endpoint: process.env.NEXT_PUBLIC_LAMATIC_ENDPOINT ?? "",
- projectId: process.env.NEXT_PUBLIC_LAMATIC_PROJECT_ID ?? "",
- apiKey: process.env.LAMATIC_API_KEY ?? "",
+ endpoint: requireEnv("LAMATIC_API_URL"),
+ projectId: requireEnv("LAMATIC_PROJECT_ID"),
+ apiKey: requireEnv("LAMATIC_API_KEY"),
},
flows: {
pricing: {
name: "Forge Pricing",
- workflowId: process.env.NEXT_PUBLIC_FLOW_PRICING ?? "",
+ workflowId: requireEnv("FLOW_PRICING"),
@@
tradeoff: {
name: "Forge Tradeoff",
- workflowId: process.env.NEXT_PUBLIC_FLOW_TRADEOFF ?? "",
+ workflowId: requireEnv("FLOW_TRADEOFF"),
@@
contract: {
name: "Forge Contract",
- workflowId: process.env.NEXT_PUBLIC_FLOW_CONTRACT ?? "",
+ workflowId: requireEnv("FLOW_CONTRACT"),
@@
invoice: {
name: "Forge Invoice",
- workflowId: process.env.NEXT_PUBLIC_FLOW_INVOICE ?? "",
+ workflowId: requireEnv("FLOW_INVOICE"),Also applies to: 10-10, 25-25, 47-47, 70-70
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@kits/forge/apps/orchestrate.js` around lines 3 - 5, The current config
silently defaults endpoint, projectId and apiKey to empty strings (endpoint,
projectId, apiKey) which delays errors; instead validate
process.env.NEXT_PUBLIC_LAMATIC_ENDPOINT,
process.env.NEXT_PUBLIC_LAMATIC_PROJECT_ID and process.env.LAMATIC_API_KEY at
module initialization and throw a clear Error (or assert) if any are missing so
the app fails fast on startup; update the code around where
endpoint/projectId/apiKey are set to remove the "?? ''" defaults and add a small
validation block that constructs a helpful message listing the missing env var
names before throwing.
| "react": "^18", | ||
| "react-dom": "^18", | ||
| "lamatic": "latest", | ||
| "clsx": "^2.1.1", | ||
| "tailwind-merge": "^2.3.0", | ||
| "lucide-react": "^0.400.0", | ||
| "react-markdown": "^9.0.0", | ||
| "react-signature-canvas": "^1.0.7" | ||
| }, | ||
| "devDependencies": { | ||
| "typescript": "^5", | ||
| "@types/node": "^20", | ||
| "@types/react": "^18", | ||
| "@types/react-dom": "^18", | ||
| "@types/react-signature-canvas": "^1.0.5", | ||
| "tailwindcss": "^3.4.1", | ||
| "autoprefixer": "^10.4.19", | ||
| "postcss": "^8.4.38", | ||
| "eslint": "^8", | ||
| "eslint-config-next": "14.2.5" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="kits/forge/apps/package.json"
echo "== $FILE =="
ls -l "$FILE"
echo
nl -ba "$FILE" | sed -n '1,120p'
echo
echo "== deps versions (prod + dev) =="
rg -n '"(react|react-dom|lamatic|clsx|tailwind-merge|lucide-react|react-markdown|react-signature-canvas|typescript|`@types/node`|`@types/react`|`@types/react-dom`|`@types/react-signature-canvas`|tailwindcss|autoprefixer|postcss|eslint|eslint-config-next)"\s*:\s*".*"' "$FILE" || trueRepository: Lamatic/AgentKit
Length of output: 234
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="kits/forge/apps/package.json"
echo "== $FILE =="
ls -l "$FILE"
echo
python3 - <<'PY'
import json, pathlib
p = pathlib.Path("kits/forge/apps/package.json")
txt = p.read_text()
print("---- raw snippet (first 160 lines) ----")
for i,line in enumerate(txt.splitlines(), start=1):
if i>160: break
print(f"{i:4d}: {line}")
print("---- parsed versions (deps+devDeps) ----")
data = json.loads(txt)
for section in ("dependencies","devDependencies"):
d = data.get(section, {})
for k in sorted(d.keys()):
print(f"{section}.{k} = {d[k]}")
PY
echo
echo "== ranges/latest check (matches ^, ~, latest) =="
python3 - <<'PY'
import json, pathlib, re
p = pathlib.Path("kits/forge/apps/package.json")
data = json.loads(p.read_text())
keys = []
bad = []
for section in ("dependencies","devDependencies"):
for k,v in data.get(section, {}).items():
if v == "latest" or re.match(r'^[\^~]', v) or v=="*" :
bad.append((section,k,v))
if not bad:
print("No ranges/tilde/caret/latest/* found in the selected sections.")
else:
for item in sorted(bad):
print("BAD:", ".".join(item[:2]), "=", item[2])
PYRepository: Lamatic/AgentKit
Length of output: 2648
Mission directive: pin every dependency version in kits/forge/apps/package.json (no ranges, no latest)
This kit’s package.json still uses caret ranges and latest, which breaks reproducible kit installs/builds:
dependencies:react^18,react-dom^18,lamaticlatest,clsx^2.1.1,tailwind-merge^2.3.0,lucide-react^0.400.0,react-markdown^9.0.0,react-signature-canvas^1.0.7devDependencies:typescript^5,@types/node^20,@types/react^18,@types/react-dom^18,@types/react-signature-canvas^1.0.5,tailwindcss^3.4.1,autoprefixer^10.4.19,postcss^8.4.38,eslint^8
Pin these to exact versions (keep already-exact next / eslint-config-next).
[kill-switch: no more ^/latest in the kit manifest]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@kits/forge/apps/package.json` around lines 13 - 32, Update
kits/forge/apps/package.json by replacing all non-exact dependency specifiers
with exact versions: change "react", "react-dom", "lamatic", "clsx",
"tailwind-merge", "lucide-react", "react-markdown", and "react-signature-canvas"
in the "dependencies" section and "typescript", "`@types/node`", "`@types/react`",
"`@types/react-dom`", "`@types/react-signature-canvas`", "tailwindcss",
"autoprefixer", "postcss", and "eslint" in "devDependencies" from ranges or
"latest" to concrete version strings (no ^, ~, or "latest"); keep the existing
exact entries such as "eslint-config-next" unchanged. Ensure each entry is a
fixed version literal (e.g., "18.2.0" style) and run a quick install to verify
no conflicts.
| - line_items: use exactly what is provided. Do not modify amounts. - notes: include the freelancer's notes if provided, otherwise omit | ||
| or leave as empty string. |
There was a problem hiding this comment.
Mission directive: remove conflicting notes instructions to avoid malformed output.
You require a fixed key set, then allow omitting notes. That contradiction can produce schema drift and break downstream parsing.
Proposed prompt patch
-- line_items: use exactly what is provided. Do not modify amounts. - notes: include the freelancer's notes if provided, otherwise omit
-or leave as empty string.
+- line_items: use exactly what is provided. Do not modify amounts.
+- notes: always include the "notes" key; use freelancer notes when provided, otherwise set it to an empty string "".📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - line_items: use exactly what is provided. Do not modify amounts. - notes: include the freelancer's notes if provided, otherwise omit | |
| or leave as empty string. | |
| - line_items: use exactly what is provided. Do not modify amounts. | |
| - notes: always include the "notes" key; use freelancer notes when provided, otherwise set it to an empty string "". |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@kits/forge/prompts/forge-invoice_llmnode-invoice_system_0.md` around lines 44
- 45, The prompt currently contains conflicting directives for the output
schema: one line mandates a fixed keyset including "line_items" while another
allows omitting or leaving "notes" empty, which can cause schema drift; update
the prompt in forge-invoice_llmnode-invoice_system_0.md to remove the
contradictory allowance so the keys are consistent — keep "line_items: use
exactly what is provided. Do not modify amounts." and change the "notes"
instruction to a single clear rule (either "notes: include the freelancer's
notes if provided, otherwise set as empty string" OR "notes: always include the
field, empty string if not provided") so downstream parsers receive a stable
schema.
:robot_face: AgentKit Structural ValidationNew Contributions Detected
Check Results
|
|
Failure recorded at 2026-06-03T15:50:21Z UTC. If this PR is not fixed within 4 weeks it will be automatically closed. |
|
Hello @cyber-turtle in the lamatic.config.ts file can you replace single quotes with double quotes in Kit? Right now it is 'kit' instead of "kit". More context to what to what: Line 5 in the .ts file (type: 'kit' as const,) to (type: "kit" as const,) Thanks! |
|
/validate |
|
📡 Running Studio validation — results will appear here shortly. |
What This Kit Does
Forge is a 4-flow autonomous freelance documentation agent designed to protect freelancers by automating professional contracts and invoices in under 60 seconds.
Users submit project details, and the agent triggers a multi-step AI pipeline: first, it performs a Pricing Analysis to suggest market-calibrated rates; second, it runs a Governing Law Tradeoff to recommend the best jurisdiction based on the freelancer's specific concerns (IP, payment, or disputes); and finally, it synthesizes a full 13-section Services Agreement and a matching Professional Invoice.
Both documents are rendered in a premium glassmorphic interface, support digital signatures, and can be exported as perfectly paginated, multi-page PDFs.
Providers & Prerequisites
/appsdirectory).How to Run Locally
cd kits/forge/appsnpm installcp .env.example .env.localand fill in your 4 Lamatic Flow IDs and API Keynpm run devLive Preview
Live App: https://forge-wheat-one.vercel.app/
Lamatic Flows
8738b556-9a25-41e9-9233-03091e4e375964a8c279-ef27-4632-a5ec-9ec3f752674e6e5e8e78-c89b-449e-b9ef-6090e72f05645788478d-6490-4107-afb9-470086c8a77dPR Checklist
1. Select Contribution Type
kits/<category>/<kit-name>/)bundles/<bundle-name>/)templates/<template-name>/)2. General Requirements
kebab-caseand matches the flow IDREADME.md(purpose, setup, usage)3. File Structure (Check what applies)
config.jsonpresent with valid metadata (name, description, tags, steps, author, env keys)flows/<flow-name>/(where applicable) include:config.json(Lamatic flow export)inputs.jsonmeta.jsonREADME.md.env.examplewith placeholder values only (kits only)config.jsonnode graphs (changes via Lamatic Studio export)4. Validation
npm install && npm run devworks locally (kits: UI runs; bundles/templates: flows are valid)[kit] Add <name> for <use case>)Files Added - Complete Inventory
Configuration & Build Files (8 files)
@/*path aliasDocumentation (2 files)
Root Layout & Pages (2 files)
Multi-Step Wizard (2 files)
Wizard Steps (4 components)
Preview Pages (2 files)
Document Renderers (2 components)
UI Components (6 files)
Styling (1 file)
Utilities & Helpers (5 files)
Backend (2 files)
Configuration Object (1 file)
Flow Definitions (4 files)
LLM Model Configs (4 files)
LLM System Prompts (4 files)
LLM User Prompts (4 files)
Constitution (1 file)
Lamatic Flow Architecture & Node Types
Unified Node Pattern (All 4 Flows)
Each flow uses 3 core node types wired in sequence:
triggerNode (type:
triggerNode)advance_schemadescribing required input fieldsLLMNode (type:
dynamicNode+ generativeModel)generativeModelNameinput to select modelresponseNode (type:
responseNode)4-Step Sequential Pipeline
Step 1 → Step 2: Pricing Flow
Step 2 → Step 3: Tradeoff Flow
Step 3 → Step 4 (Parallel): Contract Flow
Step 4 (Parallel): Invoice Flow
Flow Dependency Graph
Key Design Principles