---
name: forge-full-output
description: Anti-truncation discipline. Forces complete code generation, bans `// ... rest of the file` placeholders and "omitted for brevity" prose. Specifies how to split cleanly when a file is genuinely too long for one response. Contains the banned-phrases list, the explicit-split format, and a worked example. Use when an agent keeps producing partial files the user has to ask to "continue."
license: MIT
---

# forge-full-output

You are producing code that will be saved to a file and executed. Default agent output truncates with `// ... rest of the function` or `# (other methods omitted for brevity)` when the file is long. The user then has to ask you to "continue" or "show the full file," wastes a round-trip, and often ends up with mangled paste-together output. This skill exists to stop that.

The contract: **when you write a file, you write the entire file.** Never a placeholder, never an ellipsis, never a "and so on for the other cases." If the file is too long for one response, you split cleanly with explicit markers, not silently.

## Quick reference (the things you must never ship)

1. `// ...` or `# ...` or `/* ... */` standing in for real code.
2. "rest of the implementation" inside a code block.
3. "omitted for brevity" anywhere.
4. "similar pattern for the other cases" inside code.
5. "additional handlers go here" as a placeholder.
6. "see above" inside a function body.
7. A function declaration with an empty body and a `TODO`.
8. Bare `...` as a comment on its own line in code.
9. Silently producing the start of a function with no end.
10. A code block of "Showing only the changed methods" without saying so explicitly.

## Hard rules

### Banned patterns

**1. No `// ...` or `# ...` or `/* ... */` standing in for real code.** A literal ellipsis in a code block is the single most common partial-output failure mode.

```ts
// BAD
class OrderService {
  charge(order: Order) {
    this.validate(order);
    // ... rest of the function
  }
  refund(order: Order) { /* similar pattern */ }
  // additional methods omitted for brevity
}

// GOOD - write the full code
class OrderService {
  charge(order: Order) {
    this.validate(order);
    const result = this.stripe.charge(order.total_cents, order.currency);
    if (!result.ok) throw new ChargeFailedError(order.id);
    return result.value;
  }
  refund(order: Order) {
    this.validate(order);
    const result = this.stripe.refund(order.charge_id);
    if (!result.ok) throw new RefundFailedError(order.id);
    return result.value;
  }
  cancel(order: Order) {
    if (order.status === "fulfilled") throw new CannotCancelError(order.id);
    order.status = "cancelled";
    return this.repo.save(order);
  }
}
```

**2. No prose inside a code block standing in for code.** Banned phrases:

- "rest of the implementation"
- "remaining methods omitted"
- "similar pattern for other cases"
- "see above"
- "abbreviated for clarity"
- "additional handlers go here"
- "...etc..."

**3. No "no changes needed" comments where code should be.** If a section is unchanged, either show it in full or use a diff format where unchanged lines are implicit. Do not write `// (unchanged)` in place of code that should appear.

**4. No partial imports.** If you reference a symbol, the import is present. Never `import { ..., the_thing_you_use }`.

**5. No partial function bodies.** A function definition either has its complete body or it does not appear. No empty bodies with a `TODO`.

### Format

**6. Every code block is complete and runnable on its own (or as a clearly named partial).** A partial is allowed if the file has been clearly labeled: "Showing only the changed methods. Full file available on request." But the partial itself is complete - every line that should be in the partial is in the partial.

**7. When showing a diff, use unified diff format with proper context lines.** Not handwritten "the rest stays the same" prose.

```diff
--- a/src/handlers/orders.ts
+++ b/src/handlers/orders.ts
@@ -42,8 +42,11 @@ export async function POST(req: Request) {
   if (!parsed.success) {
     return Errors.validationFailed(c, issuesToFields(parsed.error));
   }
+
+  // forge-validation: compute server-side, never trust client total
+  const total_cents = input.items.reduce((acc, i) => acc + i.unit_price_cents * i.quantity, 0);

-  const total_cents = input.total;
   const result = await createOrder({
     customer_id: input.customer_id,
```

**8. Filenames stated above every code block.**

````markdown
**src/handlers/orders.ts**
```ts
// full content
```

**src/lib/cursor.ts**
```ts
// full content
```
````

### Handling token limits

**9. If a single file is genuinely too long for one response, split with explicit markers.**

````markdown
**src/big-file.ts** (part 1 of 2, lines 1-450)

```ts
[code]
```

--- continued in next response ---
````

In the follow-up:

````markdown
**src/big-file.ts** (part 2 of 2, lines 451-900)

```ts
[code]
```

--- end of file ---
````

**10. Pick the split point at a function or class boundary, not mid-statement.** Ugly splits force the user to fix the join.

**11. Never silently truncate to "fit."** If you sense the response will get cut off, stop earlier at a clean boundary and say so, instead of producing the start of a function that has no end.

### Self-check before sending

**12. Read your own output as if it were going into a compiler.** Every opening brace has a matching close. Every async function has a return path. Every imported symbol is used or removed.

**13. If you wrote a function signature, the body is complete.**

**14. Tests are complete.** Test files often suffer from "and 14 more cases below" placeholder syndrome. If you list a test, write the test.

## Common AI-output patterns to reject

| Pattern | Example | Fix |
| --- | --- | --- |
| Ellipsis comment | `// ... rest of the implementation` | Write the actual code |
| Omitted-for-brevity prose | `// (similar to above, omitted)` | Write the actual code |
| Bare ellipsis line | `// ...` on its own line | Write the actual code |
| Method shortcut | `refund(o) { /* ... */ }` | Write the actual body |
| Pseudo-todo | `function pay() { /* TODO */ }` | Implement it, or do not include it |
| "Continued from previous" with no marker | Just appended text | Explicit `(part 2 of 2)` header + clean split |
| Partial import | `import { a, b, ..., x } from "..."` | Full import list |
| Snippet of changed lines, unlabeled | Looks like full file | Label as partial or write the full file |

## When this skill is the wrong tool

Legitimate cases where you do not write the full file:

**15. The user explicitly asked for an outline or sketch.** "Just show me the function signature for now."

**16. The user is iterating on one function** and the rest is irrelevant.

**17. Explaining a concept** where the code is illustrative, not executable.

In those cases, **write a clear partial with a labeled boundary**, not silent truncation:

````markdown
**Partial: just the new method (in src/orders.ts)**

```ts
async cancel(id: OrderId): Promise<Result<Order, CancelError>> {
  const result = await this.db.update(
    "UPDATE orders SET status = 'cancelled' WHERE id = $1 AND status NOT IN ('cancelled', 'fulfilled') RETURNING *",
    [id],
  );
  if (result.rowCount === 1) return ok(rowToOrder(result.rows[0]));
  return err({ code: "not_found" });
}
```

This is the only new method. The rest of `OrderService` is unchanged.
````

## Worked example: bad → good

Bad:

````markdown
Here's the handler:

```ts
export async function POST(req: Request) {
  const body = await req.json();
  // validate input
  // ...

  const order = await db.orders.create(body);
  return new Response(JSON.stringify({ id: order.id }), { status: 201 });
}
```

Let me know if you need the full implementation.
````

Good:

````markdown
**src/handlers/orders.ts**

```ts
import { z } from "zod";
import { db } from "../db.js";

const CreateOrderInput = z.object({
  customer_id: z.string().uuid(),
  currency: z.enum(["USD", "EUR", "KZT"]),
  items: z.array(z.object({
    sku: z.string().min(1),
    quantity: z.number().int().positive(),
    unit_price_cents: z.number().int().nonnegative(),
  })).min(1).max(50),
});

export async function POST(req: Request) {
  let body: unknown;
  try {
    body = await req.json();
  } catch {
    return Response.json(
      { error: { code: "invalid_json", message: "Body is not valid JSON." } },
      { status: 400 },
    );
  }

  const parsed = CreateOrderInput.safeParse(body);
  if (!parsed.success) {
    return Response.json(
      {
        error: {
          code: "validation_failed",
          message: "Validation failed.",
          fields: parsed.error.issues.map((i) => ({ path: i.path.join("."), code: i.code })),
        },
      },
      { status: 400 },
    );
  }
  const input = parsed.data;

  const total_cents = input.items.reduce(
    (acc, i) => acc + i.unit_price_cents * i.quantity,
    0,
  );

  const order = await db.orders.create({
    customer_id: input.customer_id,
    currency: input.currency,
    total_cents,
  });

  return Response.json(
    { id: order.id, total_cents: order.total_cents, status: order.status },
    { status: 201, headers: { Location: `/v1/orders/${order.id}` } },
  );
}
```
````

What this does right: filename stated; all imports present; full input validation; full error responses with structured shape; full total calculation; full DB call; full success response with Location header; no `// ...` anywhere; no "let me know if you need more."

## Workflow

When producing code:

1. **Estimate file length before starting.** Under 500 lines, write it all in one response. Over 500, plan the split.
2. **Write top to bottom, no skipping.** Resist "let me show you the key parts."
3. **At the end, scan for banned patterns.** If present, replace with real code.
4. **If you run out of tokens, mark the cut point explicitly and offer to continue.**
5. **Do not summarize the file after writing it.** The file is the artifact.

## Verification

```bash
bash skills/output/forge-full-output/verify/check_truncation.sh path/to/file
```

Flags: ellipsis placeholder comments, truncation prose ("rest of the file"), bare ellipsis lines.

## When to skip this skill

- User explicitly asked for an outline or sketch.
- User is iterating on one function and the rest is irrelevant.
- You are explaining a concept and the code block is illustrative, not executable.

## Related skills

- [`forge-code-review`](../../dx/forge-code-review/SKILL.md) - reviewing for truncation as a blocker.
- [`forge-prompt-engineering`](../../llm/forge-prompt-engineering/SKILL.md) - prompts that explicitly demand full output.
