moe-reference 1.5.0

Embedded reference documentation for Albert CLI — production patterns, security, and best practices
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
---
role: antipatterns
summary: |
  Common mistakes and patterns to avoid in OpenProse programs.
  Read this file to identify and fix problematic code patterns.
see-also:
  - prose.md: Execution semantics, how to run programs
  - compiler.md: Full syntax grammar, validation rules
  - patterns.md: Recommended design patterns
---

# OpenProse Antipatterns

This document catalogs patterns that lead to brittle, expensive, slow, or unmaintainable programs. Each antipattern includes recognition criteria and remediation guidance.

---

## Structural Antipatterns

#### god-session

A single session that tries to do everything. God sessions are hard to debug, impossible to parallelize, and produce inconsistent results.

```prose
# Bad: One session doing too much
session """
  Read all the code in the repository.
  Identify security vulnerabilities.
  Find performance bottlenecks.
  Check for style violations.
  Generate a comprehensive report.
  Suggest fixes for each issue.
  Prioritize by severity.
  Create a remediation plan.
"""
```

**Why it's bad**: The session has no clear completion criteria. It mixes concerns that could be parallelized. Failure anywhere fails everything.

**Fix**: Decompose into focused sessions:

```prose
# Good: Focused sessions
parallel:
  security = session "Identify security vulnerabilities"
  perf = session "Find performance bottlenecks"
  style = session "Check for style violations"

session "Synthesize findings and prioritize by severity"
  context: { security, perf, style }

session "Create remediation plan"
```

#### sequential-when-parallel

Running independent operations sequentially when they could run concurrently. Wastes wall-clock time.

```prose
# Bad: Sequential independent work
let market = session "Research market"
let tech = session "Research technology"
let competition = session "Research competition"

session "Synthesize"
  context: [market, tech, competition]
```

**Why it's bad**: Total time is sum of all research times. Each session waits for the previous one unnecessarily.

**Fix**: Parallelize independent work:

```prose
# Good: Parallel independent work
parallel:
  market = session "Research market"
  tech = session "Research technology"
  competition = session "Research competition"

session "Synthesize"
  context: { market, tech, competition }
```

#### spaghetti-context

Context passed haphazardly without clear data flow. Makes programs hard to understand and modify.

```prose
# Bad: Unclear what context is actually used
let a = session "Step A"
let b = session "Step B"
  context: a
let c = session "Step C"
  context: [a, b]
let d = session "Step D"
  context: [a, b, c]
let e = session "Step E"
  context: [a, c, d]  # Why not b?
let f = session "Step F"
  context: [a, b, c, d, e]  # Everything?
```

**Why it's bad**: Unclear which sessions depend on which outputs. Hard to parallelize or refactor.

**Fix**: Minimize context to actual dependencies:

```prose
# Good: Clear, minimal dependencies
let research = session "Research"
let analysis = session "Analyze"
  context: research
let recommendations = session "Recommend"
  context: analysis  # Only needs analysis, not research
let report = session "Report"
  context: recommendations
```

#### parallel-then-synthesize

Spawning parallel agents for related analytical work, then synthesizing, when a single focused agent could do the entire job more efficiently.

```prose
# Antipattern: Parallel investigation + synthesis
parallel:
  code = session "Analyze code path"
  logs = session "Analyze logs"
  context = session "Analyze execution context"

synthesis = session "Synthesize all findings"
  context: { code, logs, context }
# 4 LLM calls, coordination overhead, fragmented context
```

**Why it's bad**: For related analysis that feeds into one conclusion, the coordination overhead and context fragmentation often outweigh parallelism benefits. Each parallel agent sees only part of the picture.

**Fix**: Use a single focused agent with multi-step instructions:

```prose
# Good: Single comprehensive investigator
diagnosis = session "Investigate the error"
  prompt: """Analyze comprehensively:
  1. Check the code path that produced the error
  2. Examine logs for timing and state
  3. Review execution context
  Synthesize into a unified diagnosis."""
# 1 LLM call, full context, no coordination
```

**When parallel IS right**: When analyses are truly independent (security vs performance), when you want diverse perspectives that shouldn't influence each other, or when the work is so large it genuinely benefits from division.

#### copy-paste-workflows

Duplicating session sequences instead of using blocks. Leads to inconsistent changes and maintenance burden.

```prose
# Bad: Duplicated workflow
session "Security review of module A"
session "Performance review of module A"
session "Synthesize reviews of module A"

session "Security review of module B"
session "Performance review of module B"
session "Synthesize reviews of module B"

session "Security review of module C"
session "Performance review of module C"
session "Synthesize reviews of module C"
```

**Why it's bad**: If the workflow needs to change, you must change it everywhere. Easy to miss one.

**Fix**: Extract into a block:

```prose
# Good: Reusable block
block review-module(module):
  parallel:
    sec = session "Security review of {module}"
    perf = session "Performance review of {module}"
  session "Synthesize reviews of {module}"
    context: { sec, perf }

do review-module("module A")
do review-module("module B")
do review-module("module C")
```

---

## Robustness Antipatterns

#### unbounded-loop

A loop without max iterations. Can run forever if the condition is never satisfied.

```prose
# Bad: No escape hatch
loop until **the code is perfect**:
  session "Improve the code"
```

**Why it's bad**: "Perfect" may never be achieved. The program could run indefinitely, consuming resources.

**Fix**: Always specify `max:`:

```prose
# Good: Bounded iteration
loop until **the code is perfect** (max: 10):
  session "Improve the code"
```

#### optimistic-execution

Assuming everything will succeed. No error handling for operations that can fail.

```prose
# Bad: No error handling
session "Call external API"
session "Process API response"
session "Store results in database"
session "Send notification"
```

**Why it's bad**: If the API fails, subsequent sessions receive no valid input. Silent corruption.

**Fix**: Handle failures explicitly:

```prose
# Good: Error handling
try:
  let response = session "Call external API"
    retry: 3
    backoff: "exponential"
  session "Process API response"
    context: response
catch as err:
  session "Handle API failure gracefully"
    context: err
```

#### ignored-errors

Using `on-fail: "ignore"` when failures actually matter. Masks problems that should surface.

```prose
# Bad: Ignoring failures that matter
parallel (on-fail: "ignore"):
  session "Charge customer credit card"
  session "Ship the product"
  session "Send confirmation email"

session "Order complete!"  # But was it really?
```

**Why it's bad**: The order might be marked complete even if payment failed.

**Fix**: Use appropriate failure policy:

```prose
# Good: Fail-fast for critical operations
parallel:  # Default: fail-fast
  payment = session "Charge customer credit card"
  inventory = session "Reserve inventory"

# Only ship if both succeeded
session "Ship the product"
  context: { payment, inventory }

# Email can fail without blocking
try:
  session "Send confirmation email"
catch:
  session "Queue email for retry"
```

#### vague-discretion

Discretion conditions that are ambiguous or unmeasurable.

```prose
# Bad: What does "good enough" mean?
loop until **the output is good enough**:
  session "Improve output"

# Bad: Highly subjective
if **the user will be happy**:
  session "Ship it"
```

**Why it's bad**: The VM has no clear criteria for evaluation. Results are unpredictable.

**Fix**: Provide concrete, evaluatable criteria:

```prose
# Good: Specific criteria
loop until **all tests pass and code coverage exceeds 80%** (max: 10):
  session "Improve test coverage"

# Good: Observable conditions
if **the response contains valid JSON with all required fields**:
  session "Process the response"
```

#### catch-and-swallow

Catching errors without meaningful handling. Hides problems without solving them.

```prose
# Bad: Silent swallow
try:
  session "Critical operation"
catch:
  # Nothing here - error disappears
```

**Why it's bad**: Errors vanish. No recovery, no logging, no visibility.

**Fix**: Handle errors meaningfully:

```prose
# Good: Meaningful handling
try:
  session "Critical operation"
catch as err:
  session "Log error for investigation"
    context: err
  session "Execute fallback procedure"
  # Or rethrow if unrecoverable:
  throw
```

---

## Cost Antipatterns

#### opus-for-everything

Using the most powerful (expensive) model for all tasks, including trivial ones.

```prose
# Bad: Opus for simple classification
agent classifier:
  model: opus
  prompt: "Categorize items as: spam, not-spam"

# Expensive for a binary classification
for email in emails:
  session: classifier
    prompt: "Classify: {email}"
```

**Why it's bad**: Opus costs significantly more than haiku. Simple tasks don't benefit from advanced reasoning.

**Fix**: Match model to task complexity:

```prose
# Good: Haiku for simple tasks
agent classifier:
  model: haiku
  prompt: "Categorize items as: spam, not-spam"
```

#### context-bloat

Passing excessive context that the session doesn't need.

```prose
# Bad: Passing everything
let full_codebase = session "Read entire codebase"
let all_docs = session "Read all documentation"
let history = session "Get full git history"

session "Fix the typo in the README"
  context: [full_codebase, all_docs, history]  # Massive overkill
```

**Why it's bad**: Large contexts slow processing, increase costs, and can confuse the model with irrelevant information.

**Fix**: Pass minimal relevant context:

```prose
# Good: Minimal context
let readme = session "Read the README file"

session "Fix the typo in the README"
  context: readme
```

#### unnecessary-iteration

Looping when a single session would suffice.

```prose
# Bad: Loop for what could be one call
let items = ["apple", "banana", "cherry"]
for item in items:
  session "Describe {item}"
```

**Why it's bad**: Three sessions when one could handle all items. Session overhead multiplied.

**Fix**: Batch when possible:

```prose
# Good: Batch processing
let items = ["apple", "banana", "cherry"]
session "Describe each of these items: {items}"
```

#### redundant-computation

Computing the same thing multiple times.

```prose
# Bad: Redundant research
session "Research AI safety for security review"
session "Research AI safety for ethics review"
session "Research AI safety for compliance review"
```

**Why it's bad**: Same research done three times with slightly different framing.

**Fix**: Compute once, use many times:

```prose
# Good: Compute once
let research = session "Comprehensive research on AI safety"

parallel:
  session "Security review"
    context: research
  session "Ethics review"
    context: research
  session "Compliance review"
    context: research
```

---

## Performance Antipatterns

#### eager-over-computation

Computing everything upfront when only some results might be needed.

```prose
# Bad: Compute all branches even if only one is needed
parallel:
  simple_analysis = session "Simple analysis"
    model: haiku
  detailed_analysis = session "Detailed analysis"
    model: sonnet
  deep_analysis = session "Deep analysis"
    model: opus

# Then only use one based on some criterion
choice **appropriate depth**:
  option "Simple":
    session "Use simple"
      context: simple_analysis
  option "Detailed":
    session "Use detailed"
      context: detailed_analysis
  option "Deep":
    session "Use deep"
      context: deep_analysis
```

**Why it's bad**: All three analyses run even though only one is used.

**Fix**: Compute lazily:

```prose
# Good: Only compute what's needed
let initial = session "Initial assessment"
  model: haiku

choice **appropriate depth based on initial assessment**:
  option "Simple":
    session "Simple analysis"
      model: haiku
  option "Detailed":
    session "Detailed analysis"
      model: sonnet
  option "Deep":
    session "Deep analysis"
      model: opus
```

#### over-parallelization

Parallelizing so aggressively that overhead dominates or resources are exhausted.

```prose
# Bad: 100 parallel sessions
parallel for item in large_collection:  # 100 items
  session "Process {item}"
```

**Why it's bad**: May overwhelm the system. Coordination overhead can exceed parallelism benefits.

**Fix**: Batch or limit concurrency:

```prose
# Good: Process in batches
for batch in batches(large_collection, 10):
  parallel for item in batch:
    session "Process {item}"
```

#### premature-parallelization

Parallelizing tiny tasks where sequential would be simpler and fast enough.

```prose
# Bad: Parallel overkill for simple tasks
parallel:
  a = session "Add 2 + 2"
  b = session "Add 3 + 3"
  c = session "Add 4 + 4"
```

**Why it's bad**: Coordination overhead exceeds task time. Sequential would be simpler and possibly faster.

**Fix**: Keep it simple:

```prose
# Good: Sequential for trivial tasks
session "Add 2+2, 3+3, and 4+4"
```

#### synchronous-fire-and-forget

Waiting for operations whose results you don't need.

```prose
# Bad: Waiting for logging
session "Do important work"
session "Log the result"  # Don't need to wait for this
session "Continue with next important work"
```

**Why it's bad**: Main workflow blocked by non-critical operation.

**Fix**: Use appropriate patterns for fire-and-forget operations, or batch logging:

```prose
# Better: Batch non-critical work
session "Do important work"
session "Continue with next important work"
# ... more important work ...

# Log everything at the end or async
session "Log all operations"
```

---

## Maintainability Antipatterns

#### magic-strings

Hardcoded prompts repeated throughout the program.

```prose
# Bad: Same prompt in multiple places
session "You are a helpful assistant. Analyze this code for bugs."
# ... later ...
session "You are a helpful assistant. Analyze this code for bugs."
# ... even later ...
session "You are a helpful assistent. Analyze this code for bugs."  # Typo!
```

**Why it's bad**: Inconsistency when updating. Typos go unnoticed.

**Fix**: Use agents:

```prose
# Good: Single source of truth
agent code-analyst:
  model: sonnet
  prompt: "You are a helpful assistant. Analyze code for bugs."

session: code-analyst
  prompt: "Analyze the auth module"
session: code-analyst
  prompt: "Analyze the payment module"
```

#### opaque-workflow

No structure or comments indicating what's happening.

```prose
# Bad: What is this doing?
let x = session "A"
let y = session "B"
  context: x
parallel:
  z = session "C"
    context: y
  w = session "D"
session "E"
  context: [z, w]
```

**Why it's bad**: Impossible to understand, debug, or modify.

**Fix**: Use meaningful names and structure:

```prose
# Good: Clear intent
# Phase 1: Research
let research = session "Gather background information"

# Phase 2: Analysis
let analysis = session "Analyze research findings"
  context: research

# Phase 3: Parallel evaluation
parallel:
  technical_eval = session "Technical feasibility assessment"
    context: analysis
  business_eval = session "Business viability assessment"
    context: analysis

# Phase 4: Synthesis
session "Create final recommendation"
  context: { technical_eval, business_eval }
```

#### implicit-dependencies

Relying on conversation history rather than explicit context.

```prose
# Bad: Implicit state
session "Set the project name to Acme"
session "Set the deadline to Friday"
session "Now create a project plan"  # Hopes previous info is remembered
```

**Why it's bad**: Relies on VM implementation details. Fragile across refactoring.

**Fix**: Explicit context:

```prose
# Good: Explicit state
let config = session "Define project: name=Acme, deadline=Friday"

session "Create a project plan"
  context: config
```

#### mixed-concerns-agent

Agents with prompts that cover too many responsibilities.

```prose
# Bad: Jack of all trades
agent super-agent:
  model: opus
  prompt: """
    You are an expert in:
    - Security analysis
    - Performance optimization
    - Code review
    - Documentation
    - Testing
    - DevOps
    - Project management
    - Customer communication
    When asked, perform any of these tasks.
  """
```

**Why it's bad**: No focus means mediocre results across the board. Can't optimize model choice.

**Fix**: Specialized agents:

```prose
# Good: Focused expertise
agent security-expert:
  model: sonnet
  prompt: "You are a security analyst. Focus only on security concerns."

agent performance-expert:
  model: sonnet
  prompt: "You are a performance engineer. Focus only on optimization."

agent technical-writer:
  model: haiku
  prompt: "You write clear technical documentation."
```

---

## Logic Antipatterns

#### infinite-refinement

Loops that can never satisfy their exit condition.

```prose
# Bad: Perfection is impossible
loop until **the code has zero bugs**:
  session "Find and fix bugs"
```

**Why it's bad**: Zero bugs is unachievable. Loop runs until max (if specified) or forever.

**Fix**: Use achievable conditions:

```prose
# Good: Achievable condition
loop until **all known bugs are fixed** (max: 20):
  session "Find and fix the next bug"

# Or: Diminishing returns
loop until **no significant bugs found in last iteration** (max: 10):
  session "Search for bugs"
```

#### assertion-as-action

Using conditions as actions—checking something without acting on the result.

```prose
# Bad: Check but don't use result
session "Check if the system is healthy"
session "Deploy to production"  # Deploys regardless!
```

**Why it's bad**: The health check result isn't used. Deploy happens unconditionally.

**Fix**: Use conditional execution:

```prose
# Good: Act on the check
let health = session "Check if the system is healthy"

if **system is healthy**:
  session "Deploy to production"
else:
  session "Alert on-call and skip deployment"
    context: health
```

#### false-parallelism

Putting sequential-dependent operations in a parallel block.

```prose
# Bad: These aren't independent!
parallel:
  data = session "Fetch data"
  processed = session "Process the data"  # Needs data!
    context: data
  stored = session "Store processed data"  # Needs processed!
    context: processed
```

**Why it's bad**: Despite being in parallel, these must run sequentially due to dependencies.

**Fix**: Be honest about dependencies:

```prose
# Good: Sequential where needed
let data = session "Fetch data"
let processed = session "Process the data"
  context: data
session "Store processed data"
  context: processed
```

#### exception-as-flow-control

Using try/catch for expected conditions rather than exceptional errors.

```prose
# Bad: Exceptions for normal flow
try:
  session "Find the optional config file"
catch:
  session "Use default configuration"
```

**Why it's bad**: Missing config is expected, not exceptional. Obscures actual errors.

**Fix**: Use conditionals for expected cases:

```prose
# Good: Conditional for expected case
let config_exists = session "Check if config file exists"

if **config file exists**:
  session "Load configuration from file"
else:
  session "Use default configuration"
```

#### excessive-user-checkpoints

Prompting the user for decisions that have obvious or predictable answers.

```prose
# Antipattern: Asking the obvious
input "Blocking error detected. Investigate?"  # Always yes
input "Diagnosis complete. Proceed to triage?"  # Always yes
input "Tests pass. Deploy?"  # Almost always yes
```

**Why it's bad**: Each checkpoint is a round-trip waiting for user input. If the answer is predictable 90% of the time, you're adding latency for no value.

**Fix**: Auto-proceed for obvious cases, only prompt when genuinely ambiguous:

```prose
# Good: Auto-proceed with escape hatches for edge cases
if observation.blocking_error:
  # Auto-investigate (don't ask - of course we investigate errors)
  let diagnosis = do investigate(...)

  # Only ask if genuinely ambiguous
  if diagnosis.confidence == "low":
    input "Low confidence diagnosis. Proceed anyway?"

  # Auto-deploy if tests pass (but log for audit)
  if fix.tests_pass:
    do deploy(...)
```

**When checkpoints ARE right**: Irreversible actions (production deployments to critical systems), expensive operations (long-running jobs), or genuine decision points where the user's preference isn't predictable.

#### fixed-observation-window

Waiting for a predetermined duration when the signal arrived early.

```prose
# Antipattern: Fixed window regardless of findings
loop 30 times (wait: 2s each):  # Always 60 seconds
  resume: observer
    prompt: "Keep watching the stream"
# Runs all 30 iterations even if blocking error detected on iteration 1
```

**Why it's bad**: Wastes time when the answer is already known. If the observer detected a fatal error at +5 seconds, why wait another 55 seconds?

**Fix**: Use signal-driven exit conditions:

```prose
# Good: Exit on significant signal
loop until **blocking error OR completion** (max: 30):
  resume: observer
    prompt: "Watch the stream. Signal IMMEDIATELY on blocking errors."
# Exits as soon as something significant happens
```

Or use `early_exit` if your runtime supports it:

```prose
# Good: Explicit early exit
let observation = session: observer
  prompt: "Monitor for errors. Signal immediately if found."
  timeout: 120s
  early_exit: **blocking_error detected**
```

---

## Security Antipatterns

#### unvalidated-input

Passing external input directly to sessions without validation.

```prose
# Bad: Direct injection
let user_input = external_source

session "Execute this command: {user_input}"
```

**Why it's bad**: User could inject malicious prompts or commands.

**Fix**: Validate and sanitize:

```prose
# Good: Validate first
let user_input = external_source
let validated = session "Validate this input is a safe search query"
  context: user_input

if **input is valid and safe**:
  session "Search for: {validated}"
else:
  throw "Invalid input rejected"
```

#### overprivileged-agents

Agents with more permissions than they need.

```prose
# Bad: Full access for simple task
agent file-reader:
  permissions:
    read: ["**/*"]
    write: ["**/*"]
    bash: allow
    network: allow

session: file-reader
  prompt: "Read the README.md file"
```

**Why it's bad**: Task only needs to read one file but has full system access.

**Fix**: Least privilege:

```prose
# Good: Minimal permissions
agent file-reader:
  permissions:
    read: ["README.md"]
    write: []
    bash: deny
    network: deny
```

---

## Summary

Antipatterns emerge from:

1. **Laziness**: Copy-paste instead of abstraction, implicit instead of explicit
2. **Over-engineering**: Parallelizing everything, using opus for all tasks
3. **Under-engineering**: No error handling, unbounded loops, vague conditions
4. **Unclear thinking**: God sessions, mixed concerns, spaghetti context

When reviewing OpenProse programs, ask:

- Can independent work be parallelized?
- Are loops bounded?
- Are errors handled?
- Is context minimal and explicit?
- Are models matched to task complexity?
- Are agents focused and reusable?
- Would a stranger understand this code?

Fix antipatterns early. They compound over time into unmaintainable systems.