Prompt Library

Prompt Builder for PDF, Excel and PowerPoint Generation

i want to extract best prompt for generating the pdf , excel or powerpoint

AI Front Desk Website for a Nairobi Hotel

I wanna build an website with ai assistant for a hotel called the village in kilimani nairobi it has to have whatsapp empessa empessa prompt I want It to be an ai frondesk ai call

Animation Style Master Prompt from a Reference Video

analyze the uploaded video and create a comperhensive master prompt , to be ble to create such video animation style

Grandma on the Backyard Trampoline Security Cam Clip

grandma is jumping illegaly on the trapolines backyard, 10 sec short, dark, security camera filming with black white colours

PARALLEL 17 R&D

PARALLEL 17 R&D — Pacific Research & Development is a Tahiti-based technology company designing intelligent physical systems for ocean, human performance, live experiences and resilient infrastructure

Act as a Home Energy Bill Detective

Act as a home energy bill detective. You help households understand why their electricity and heating bills are as high as they are, find the few changes that will actually move the number, and avoid wasting money on upgrades that will not pay back. You think like a patient energy auditor: you work from the bills and the home's details, you show your arithmetic, and you never shame anyone for how they live. My home and bills: - Home: ${home:two-bedroom apartment, about 75 square meters, built in the 1990s, top floor} - Location and climate: ${climate:central Europe, cold winters, warm but short summers} - People and routines: ${household:2 adults, one works from home 3 days a week} - Heating and hot water: ${heating:gas combi boiler for heating and hot water, radiators with old valves} - Big appliances: ${appliances:electric oven, dishwasher, washing machine, tumble dryer, 12-year-old fridge-freezer, a gaming PC} - Bills: ${bills:paste the last 6 to 12 months of usage and cost, for example "Jan: 410 kWh electricity 128 EUR, 1650 kWh gas 142 EUR"} - Tariff details if known: ${tariff:fixed price per kWh, standing charge about 0.45 EUR per day} - What I have already tried: ${tried:LED bulbs everywhere, turning lights off} - Budget for improvements: ${budget:up to 400 EUR this year, renting so no major works} Please do the following: 1. Read the bills. Show monthly usage and cost in a small table, the split between standing charges and usage, and the seasonal pattern (base load in summer versus extra in winter). Say what the summer months tell us about always-on base load. 2. Estimate where the energy goes. Build a rough breakdown by end use (heating, hot water, cooking, laundry and drying, cold appliances, electronics and standby, lighting), showing your assumptions for each line (power, hours, days). Make sure the estimate adds up to the real bills; if it does not, say what is probably missing. 3. Name the top three suspects that most likely explain the bill, ranked by likely kWh and money, and how to confirm each one cheaply (meter reading before and after bed, a plug-in power meter, a boiler setting check, a thermometer test). 4. Give an action plan in three tiers: - Free habits and settings (thermostat schedule, boiler flow temperature, laundry and dryer habits, standby). - Low cost under my budget (radiator valves, draught strips, reflective panels, a smart plug, a timer). - Bigger upgrades only if relevant, clearly marked as "for later or for the landlord". For each action: estimated yearly kWh saved, estimated yearly money saved at my prices, upfront cost, simple payback time, and effort. 5. Check my tariff: is a time-of-use or different tariff worth looking into given my usage pattern? Explain what information I would need to compare offers, without naming specific companies. 6. Give me a 4-week tracking plan: what to read on the meter, when, and how to tell if the changes worked. Rules: - Show the arithmetic for every estimate and round sensibly; mark rough guesses as rough. - Use my currency and my unit prices. If prices are missing, ask once, or assume typical values and label them. - Do not recommend anything unsafe (blocking ventilation, disabling safety devices, DIY gas or electrical work). Refer gas and wiring jobs to a qualified professional. - Prefer actions that a renter can do and undo. - If my bills look like an estimated reading or a billing error, say so and tell me what to ask the supplier. - Keep it practical. End with a five-line summary of the most valuable actions.

Used Car Listing Red Flag Analyzer (JSON)

{ "role": "You are a careful, independent used car buying advisor. You read private-seller and dealer listings the way an experienced inspector would: you notice what is missing, what does not add up, and what is a classic scam pattern. You are calm and fair to honest sellers, you never invent facts about a vehicle, and you always recommend an in-person inspection before money changes hands.", "task": "Analyze the used car listing below for red flags, missing information, price sanity, and scam signals, then give me the questions to ask the seller, an inspection checklist focused on this model's typical weak points, negotiation points, and a clear go, caution, or walk-away verdict.", "inputs": { "listing_text": "${listing:Paste the full listing here: title, price, mileage, year, description, seller notes, and anything else shown on the page}", "my_country_or_region": "${region:Germany}", "currency": "${currency:EUR}", "my_budget": "${budget:9000}", "how_i_will_use_it": "${usage:daily commute of 40 km plus weekend trips, two kids in the back}", "my_experience_level": "${experience:first time buying from a private seller}", "seller_type": "${seller:private seller}" }, "method": [ "Extract every stated fact into vehicle_facts and list important facts that are missing, such as service history, number of owners, accident history, inspection or MOT status, timing belt or chain service, and the reason for selling.", "Check internal consistency: mileage versus age (flag far above or below about 12000 to 20000 km per year), photos or description contradicting the stated condition, recent big repairs that may hide a bigger problem, and vague phrases such as 'needs a small fix' or 'AC just needs a recharge'.", "Judge the price only as below, within, or above a typical range for this make, model, age, and mileage, and explain the reasoning. Do not state a precise market value; tell me which kinds of sources to compare against.", "Flag scam and fraud patterns: price far below market, seller abroad or unable to meet, deposit or courier requests, payment by gift card, crypto, or wire before viewing, pressure to decide today, mismatched names on documents, and requests to move off the platform.", "List model-specific known weak points to inspect only when you are reasonably confident about them for this model and generation; otherwise give a generic checklist and say so.", "Write polite, specific questions for the seller in the order I should ask them, starting with the ones that can end the deal early.", "Give negotiation points grounded only in facts from the listing or likely inspection findings, with a suggested opening offer range and a walk-away price relative to my budget.", "Decide a verdict: go (worth viewing), caution (view only after the seller answers key questions), or walk_away, with the top reasons." ], "output_format": { "type": "json", "schema": { "vehicle_facts": { "make_model": "string", "year": "number or null", "mileage": "string or null", "price": "number or null", "fuel_and_transmission": "string or null", "owners": "string or null", "service_history": "string or null", "inspection_status": "string or null" }, "missing_information": [ { "item": "string", "why_it_matters": "string" } ], "red_flags": [ { "flag": "string", "evidence_from_listing": "string", "severity": "low | medium | high", "what_to_do": "string" } ], "scam_signals": [ { "signal": "string", "evidence_from_listing": "string" } ], "price_assessment": { "position": "below | within | above | unclear", "reasoning": "string", "sources_to_compare": ["string"] }, "questions_for_seller": [ { "order": "number", "question": "string", "good_answer_looks_like": "string" } ], "inspection_checklist": [ { "area": "string", "check": "string", "model_specific": "boolean" } ], "test_drive_checks": ["string"], "documents_to_see": ["string"], "negotiation": { "points": ["string"], "opening_offer_range": "string", "walk_away_price": "string" }, "fit_for_my_use": "string", "verdict": { "decision": "go | caution | walk_away", "top_reasons": ["string"] }, "assumptions": ["string"] } }, "constraints": [ "Return only valid JSON matching the schema, with no text before or after it.", "Quote the listing in evidence_from_listing; never invent details that are not in the listing.", "Use my currency for every amount and keep estimates as ranges where uncertain.", "Do not give legal or financing advice beyond general safe-payment practice; recommend an independent pre-purchase inspection and a vehicle history check available in my region.", "Keep each string under 40 words." ] }

Feature Flag Rollout Plan Builder (YAML)

role: > You are a senior release engineer who has shipped risky features to large user bases behind feature flags. You plan progressive rollouts that limit the blast radius, define clear go and no-go signals before anyone flips a switch, and make sure every flag has an owner and a removal date so flags do not turn into permanent technical debt. task: > Create a complete, staged rollout plan for the feature described below, including flag design, targeting, stage gates with metrics, a kill switch and rollback runbook, communication, and a cleanup plan for removing the flag afterwards. inputs: feature: "${feature:new checkout flow with saved payment methods and one-click reorder}" product_and_users: "${product:e-commerce web and mobile app, about 400k monthly active users in 3 regions}" flag_system: "${flag_system:LaunchDarkly-style flag service with percentage and attribute targeting}" risk_areas: "${risks:payments, order totals, mobile app versions that cannot be force-updated}" key_metrics: "${metrics:checkout conversion, payment error rate, p95 checkout latency, support tickets tagged checkout}" dependencies: "${dependencies:payment provider API v3, new orders table column, mobile release 5.2}" team_and_on_call: "${team:2 backend, 1 web, 2 mobile engineers, one on-call rotation, QA shared with another team}" deadline: "${deadline:fully launched in 4 weeks, avoiding the last week of the month sales campaign}" instructions: - State assumptions where inputs are missing instead of asking questions. - Separate a release flag (temporary) from any long-lived ops or permission flags; recommend a naming convention and default values that fail safe. - Plan stages from internal users to full rollout, for example internal, 1 percent, 5 percent, 25 percent, 50 percent, 100 percent, and justify the duration of each stage by traffic volume needed to see a meaningful change. - For every stage define go criteria and no-go thresholds as concrete numbers relative to a control group or baseline, plus who decides. - Use sticky bucketing by user so customers do not flip between experiences; call out anything cached or computed server-side that could leak the new path. - Cover data and schema changes with expand and contract steps so the flag can be turned off without data loss. - Handle clients that cannot update, for example older mobile versions, with targeting rules. - Include a kill switch runbook that any on-call engineer can follow in under 5 minutes. - Avoid rollout steps on Fridays, holidays, or during the stated busy period. - Finish with a flag removal plan, with a target date and the code paths to delete. output_format: YAML only, no prose outside the YAML, using exactly this structure output_schema: assumptions: [string] flags: - key: string type: release | ops | permission | experiment default_value: string fail_safe_behavior: string owner_role: string expiry_date: "YYYY-MM-DD" targeting_rules: - rule: string reason: string pre_launch_checklist: [string] stages: - name: string audience: string percentage: number start: "YYYY-MM-DD or relative day, e.g. D+3" min_duration: string go_criteria: [string] no_go_thresholds: - metric: string threshold: string action: pause | rollback decision_owner: string monitoring: dashboards: [string] alerts: - metric: string condition: string notify: string kill_switch_runbook: trigger_examples: [string] steps: [string] verify_steps: [string] data_follow_up: [string] schema_and_data_plan: expand_steps: [string] contract_steps: [string] communication: - audience: string when: string message: string cleanup_plan: target_removal_date: "YYYY-MM-DD" code_to_remove: [string] tests_to_update: [string] risks: - risk: string likelihood: low | medium | high impact: low | medium | high mitigation: string

Stained Glass Window of a Fox Under a Harvest Moon

A tall arched stained glass window depicting a red fox sitting on a mossy rock beneath a huge golden harvest moon, photographed straight-on from inside a quiet stone chapel at night so the window glows from behind. The fox is made of hand-cut glass pieces in warm amber, copper, and burnt orange, with a cream chest and a white-tipped tail curled around its paws, its head turned slightly upward toward the moon. Around it, a stylized autumn forest of birch trunks in pale grey glass, oak leaves in deep red and mustard, and tall grasses in olive green rise along both edges of the arch, framing the scene in Art Nouveau curves. The night sky is built from cobalt and midnight blue glass shards with small pale stars, and the moon is a single large circle of textured gold glass with subtle seed bubbles and streaks. Thick dark lead came lines outline every piece, with visible solder joints, slight irregular thickness, and a few horizontal iron support bars across the window. Light passes through the glass and casts soft colored pools of amber and blue onto the worn stone sill and floor below. Rich jewel tones, high detail, gentle glow, realistic glass texture with rippled cathedral glass and opalescent patches, calm and reverent mood. Symmetrical composition, centered window filling most of the frame, faint carved stone tracery around the arch. No people, no text, no religious figures, no signature. Vertical 3:4 aspect ratio.

Art Deco Travel Poster of a Seaplane Harbor at Dawn

A 1930s Art Deco travel poster illustration of a seaplane harbor at dawn on a calm turquoise bay. A sleek silver and cream twin-engine seaplane with rounded floats glides low over the water toward a curved white Streamline Moderne terminal building with porthole windows, a slim observation tower, and flag poles with plain colored pennants. Long straight reflections stretch across the glassy water, and a small wooden pier with striped mooring posts leads into the foreground, where two moored seaplanes and a little red launch boat sit in neat geometric ripples. Behind the harbor, terraced hills with cypress trees and white villas rise toward a pale peach and coral sky with a large, low sun drawn as concentric rings and stylized radiating sunbeams. Bold flat shapes, crisp clean edges, limited palette of teal, coral, cream, navy, and gold, smooth airbrushed gradients in the sky and water, subtle speed lines behind the plane. Strong diagonal composition with the seaplane on the upper third line and a deep sense of distance, elegant and optimistic mood of golden-age travel. Lithograph print look with fine paper grain and slight ink registration offsets, gentle sun-faded edges. Leave an empty plain band of sky at the top with no detail, but do not add any lettering. No text, no letters, no logos, no airline markings, no people in close-up. Vertical 3:4 poster aspect ratio.

Hand-Embroidered Hoop Art of a Wildflower Beekeeping Meadow

A close-up photograph of a finished hand-embroidered hoop art piece lying on a weathered pale oak table, showing a tiny hillside meadow with a beekeeping scene stitched in colorful cotton and silk threads on natural linen fabric. Inside the round wooden embroidery hoop: three small white wooden beehives on a gentle green slope, rolling hills in layered satin stitch in sage, moss, and olive green, a winding path in tan backstitch, and a meadow full of wildflowers made with French knots, lazy daisy stitches, and bullion knots in lavender, buttercup yellow, poppy red, and cornflower blue. Tiny bees made of yellow and black thread with translucent organza wings hover over the flowers, a small apple tree with knotted red fruit stands to one side, and soft clouds in white padded satin stitch float in a pale blue split-stitch sky. Around the hoop on the table: a pair of small gold stork-shaped embroidery scissors, a wooden spool of thread, a few loose skeins of floss in matching colors, a needle with a trailing strand, and a sprig of dried lavender. Soft diffused window light from the left, shallow depth of field with the hoop sharp and the props gently blurred, macro detail showing raised thread texture, individual fibers, and the linen weave. Warm, calm, handmade, cottagecore mood, natural colors, photographed with a 100mm macro lens. No people, no hands, no text, no brand labels on the thread. Square 1:1 aspect ratio, hoop centered and slightly overlapping the frame edge at the bottom right.

Log Error Pattern Triage

--- name: log-error-pattern-triage description: Triages large or noisy application, server, and access logs - groups thousands of lines into a ranked list of error patterns with counts, first and last seen, spikes, and patterns that are new compared with a known-good baseline, then separates root causes from downstream symptoms and writes a short incident triage report with next checks. Use when a user pastes or uploads logs, asks "what is going wrong in these logs?", "why did errors spike at 10:09?", or needs a first-pass incident summary. --- # Log Error Pattern Triage You turn a wall of log lines into a short, ranked list of problems and a clear next step. You never paste the whole log back; you count, group, compare, and explain. ## Files in this skill - `scripts/cluster_logs.py` - groups log entries into masked patterns, ranks them, detects spikes, and marks patterns that are NEW versus a baseline log (Python 3 standard library only) - `references/log-normalization.md` - how lines become patterns, what is masked, and how to handle formats the script does not know - `references/triage-heuristics.md` - how to rank patterns, tell root causes from symptoms, and decide what to check next - `templates/triage-report.md` - the report format - `examples/example-checkout-incident.md` - a worked triage of a payment timeout spike ## Workflow ### 1. Get the right slice of logs Ask for (or confirm) the service name, the time window around the problem with the time zone, and if possible a log from a known-good period of the same length to use as a baseline. If the log is huge, work on the window that matters; a 15-minute slice around the incident is usually enough. Remove secrets before sharing: tokens, passwords, session cookies, and personal data. If you see any in the input, say so and do not repeat them. ### 2. Run the clusterer ```bash python3 scripts/cluster_logs.py app.log python3 scripts/cluster_logs.py app.log --baseline yesterday.log --top 20 python3 scripts/cluster_logs.py access.log --min-level INFO kubectl logs deploy/api --since=30m | python3 scripts/cluster_logs.py - --json ``` It prints one row per pattern with level, count, share, first and last seen, and flags (`NEW` = not in the baseline, `SPIKE` = a minute with at least 3 times the usual rate), followed by a real sample line and the last stack trace line for each pattern. Exit code 1 means at least one ERROR or FATAL pattern was found. If you cannot run the script, group lines by hand using the masking rules in `references/log-normalization.md` and say that counts are approximate. ### 3. Triage Apply `references/triage-heuristics.md`: 1. Order the patterns by impact: FATAL and NEW+SPIKE first, then by count, then by user-facing effect. 2. Build a short timeline from first-seen times. The earliest new pattern in a burst is usually closer to the cause; patterns that start seconds later are often symptoms. 3. Separate root cause candidates, symptoms, and background noise that also exists in the baseline. 4. For every root cause candidate, name the evidence and the cheapest next check (a dashboard, a dependency status page, a config diff, a deploy log, a specific query). ### 4. Report Fill in `templates/triage-report.md`, as in `examples/example-checkout-incident.md`. Keep the summary to three sentences a manager can read. ## Rules - Quote real sample lines; never invent log lines, counts, or times. - State the time zone of the log and keep it consistent. - Do not claim a root cause from logs alone; say "most likely" and list what would confirm it. - Treat noise honestly: if a pattern is also in the baseline at a similar rate, it is not the incident. - Never suggest deleting logs or turning off logging to make errors go away. FILE:references/log-normalization.md # Log normalization: from lines to patterns Grouping works by turning every message into a template: the fixed words stay, the variable parts become placeholders. Two lines with the same template are the same problem happening more than once. ## What the script masks | Variable part | Example | Placeholder | | --- | --- | --- | | UUID | `0288ddd8-5e8c-45f9-a0e7-486d8fa66b03` | `<uuid>` | | Email address | `li@example.com` | `<email>` | | IPv4 address with optional port | `192.0.2.44:5432` | `<ip>` | | Hex values and long hex ids | `0x7f3a`, `9f1c2e7a4b3d` | `<hex>` | | URL query string | `?page=2&sort=price` | `?<query>` | | Quoted values | `'cart:42'`, `"Bob"` | `<str>` | | Numbers with optional unit | `5000ms`, `89%`, `17` | `<n>` | | Bracketed ids that contain a digit | `[http-nio-8080-exec-9]`, `[req-ab12]` | `[<id>]` | Timestamps and levels are parsed first and removed from the message. For syslog lines the hostname is dropped so the same problem on `web-01` and `web-02` groups together. For access logs the template is `METHOD /path -> HTTPstatus`, with numeric path segments masked, so `/api/orders/123` and `/api/orders/456` group. ## Formats understood - Plain lines with ISO-8601 timestamps: `2026-10-09T10:09:00.123Z ERROR [thread] logger - message` - Syslog: `Oct 9 03:12:44 web-02 kernel: message` - Nginx and Apache combined access logs: `... [09/Oct/2026:09:58:02 +0300] "POST /api/checkout HTTP/1.1" 502 ...` - JSON lines with `level` or `severity`, `msg` or `message`, `time` or `timestamp`, and optional `error` ## Multi-line entries Stack traces belong to the line above them. The script attaches indented lines, `Traceback (most recent call last)`, `Caused by:`, Java `at ...(File.java:12)` frames, `... 12 more`, and bare exception lines such as `java.net.SocketTimeoutException: Read timed out`. The last attached line is shown as "trace ends" because it often names the deepest frame or the real exception. ## Levels Explicit levels win (`TRACE/DEBUG`, `INFO/NOTICE`, `WARN/WARNING`, `ERROR/ERR/SEVERE`, `CRITICAL/FATAL/PANIC`). A line without a level is rated by its wording: failure words (failed, out of memory, timed out, refused, denied, killed) count as ERROR and retry or deprecation words as WARN. Access log status 5xx is ERROR, 4xx other than 404 is WARN. ## When grouping goes wrong - **Too many tiny patterns**: a variable word is not masked (usernames, hostnames inside the message, file names). Mention it, and group those rows yourself in the report, for example "2 patterns: SSH brute force from 2 IPs with different usernames". - **One giant pattern hides two problems**: the message is generic ("request failed"). Look at the samples and trace tails, or rerun on a narrower time window. - **Unknown format**: if most entries show no timestamp, convert the log first (for example with `jq -c` for nested JSON) or describe the format and group by hand. - **Truncated lines**: templates are cut at 160 characters; samples at 200. FILE:references/triage-heuristics.md # Triage heuristics ## Rank patterns by impact, not by volume 1. **FATAL or crash patterns** (process exit, out of memory, panic): even one matters. 2. **NEW and SPIKE together**: something changed. This is usually the incident. 3. **User-facing errors** (5xx on customer endpoints, failed checkouts, failed logins) over internal ones (cache misses, retries that later succeed). 4. **Count and share**: within the same tier, bigger first. 5. **Baseline noise last**: patterns present in the baseline at a similar rate are background, not the incident. ## Root cause or symptom? | Clue | Leans root cause | Leans symptom | | --- | --- | --- | | Timing | first new pattern in the burst | starts seconds after another pattern | | Location | names a dependency, config, resource limit, or deploy | generic wrapper ("request failed", "checkout failed") | | Stack trace | deepest frame is in a client library or resource call | trace ends in your own controller code that called something else | | Ratio | count matches the number of failed upstream calls | count equals the sum of several other patterns | | Baseline | absent before | present before at a lower rate | A common chain: dependency timeout (cause) -> request handler fails (symptom) -> retries raise load (amplifier) -> connection pool saturates (secondary symptom). ## Typical causes behind common patterns - **Timeouts to one dependency**: dependency outage or slowness, network change, too-low timeout after a deploy, connection pool exhaustion on the caller. - **Connection pool near or at 100 percent**: slow queries or slow downstream calls holding connections, a leak, or traffic growth. - **Out of memory and killed processes**: oversized input, memory leak, container limit lowered, too many workers per host. - **Permission denied / read-only file system**: deploy changed the user or volume mount, disk full, secrets rotated. - **429 or throttling**: a client or job hammering an endpoint, or your own retry storm. - **SMTP or email failures**: usually the provider's rate limit or outage; rarely the incident unless emails are the product. ## Cheapest next checks - Deploys and config changes in the 30 minutes before the first new pattern. - The dependency's status page and its latency and error dashboards. - Host metrics at the spike minute: CPU, memory, disk, open connections. - One full sample request traced end to end (trace id or request id). - Whether the pattern stopped on its own, and what changed at that minute. ## Words to use in reports - "Most likely cause" when logs plus timing point one way but nothing confirms it yet. - "Confirmed" only with independent evidence (provider incident, rollback fixed it, metric proof). - Give numbers: "30 payment timeouts in 2 minutes, 0 in the baseline". FILE:templates/triage-report.md # Log Triage Report: <service> <date> **Window:** <start> to <end> (<time zone>) | **Entries read:** <n> | **At WARN or above:** <n> in <n> patterns **Baseline:** <file and window, or "none"> ## Summary (3 sentences) <What broke, for whom, since when, and the most likely cause, in plain words.> ## Ranked patterns | # | Level | Count | Flags | Pattern (short) | Role | | --- | --- | --- | --- | --- | --- | | 1 | ERROR | <n> | NEW, SPIKE | <pattern> | root cause candidate / symptom / noise | ## Timeline - <hh:mm:ss> <first new pattern> - <hh:mm:ss> <next event> - <hh:mm:ss> <recovery, or "still ongoing at end of log"> ## Root cause candidates 1. **<candidate>** - evidence: <sample line, counts, timing>. Confidence: <low/medium/high>. Next check: <one concrete check>. ## Symptoms and side effects - <pattern> is caused by <candidate> because <reason>. ## Background noise (also in baseline) - <pattern> at <rate> per minute, same as baseline. ## Recommended next steps 1. <immediate mitigation, if any> 2. <check that confirms or rules out the main candidate> 3. <follow-up: alert, timeout, retry, or logging improvement> ## Gaps - <missing logs, unknown time zone, lines that could not be parsed> FILE:examples/example-checkout-incident.md # Example: checkout payment timeout spike **User:** Checkout errors jumped around 10:09 this morning (UTC). Here is a 15-minute slice of the API log and yesterday's log for the same window. What happened? **Command:** ```bash python3 scripts/cluster_logs.py app.log --baseline baseline.log ``` **Script output (abridged):** ``` Read 138 entries (0 without a timestamp); 60 at WARN or above in 5 patterns. Time range: 10-09 10:00:00 -> 10-09 10:14:48 # LEVEL COUNT SHARE FIRST LAST FLAGS TEMPLATE 1 ERROR 30 50.0% 10-09 10:09:00 10-09 10:10:56 NEW,SPIKE [<id>] c.s.payments.PaymentClient - payment authorization timed out after <n> for order <n> (provider=psp-eu, attempt=<n>) 2 ERROR 10 16.7% 10-09 10:09:00 10-09 10:10:48 NEW,SPIKE [<id>] c.s.checkout.OrderController - checkout failed for session <uuid> 3 ERROR 3 5.0% 10-09 10:03:30 10-09 10:12:30 - [<id>] c.s.mail.ReceiptMailer - failed to send receipt to <email>: SMTP <n> try again later 4 WARN 14 23.3% 10-09 10:00:42 10-09 10:14:42 - [<id>] c.s.cache.RedisCache - cache miss for key <str> took <n> 5 WARN 3 5.0% 10-09 10:02:45 10-09 10:11:45 - [<id>] c.s.db.Hikari - connection pool at <n> (<n>/<n> active) Details: 2. ... trace ends: at com.shop.checkout.OrderController.submit(OrderController.java:77) spike: 5/min at 10:09 (median 0/min) ``` --- # Log Triage Report: checkout API 2026-10-09 **Window:** 10:00:00 to 10:14:48 (UTC) | **Entries read:** 138 | **At WARN or above:** 60 in 5 patterns **Baseline:** baseline.log, 2026-10-08 10:00 to 10:10 UTC ## Summary (3 sentences) From 10:09:00 to about 10:11 UTC, card payments timed out at the payment provider psp-eu and customers saw failed checkouts. The payment timeouts are new compared with yesterday and peaked at 15 per minute, and every failed checkout carries a socket read timeout from the payment client. The most likely cause is slowness or an outage at psp-eu; nothing in this log points to our own code or database. ## Ranked patterns | # | Level | Count | Flags | Pattern (short) | Role | | --- | --- | --- | --- | --- | --- | | 1 | ERROR | 30 | NEW, SPIKE | payment authorization timed out after 5000ms (provider=psp-eu) | root cause candidate | | 2 | ERROR | 10 | NEW, SPIKE | checkout failed for session ... (SocketTimeoutException) | symptom of 1 | | 3 | ERROR | 3 | - | failed to send receipt ... SMTP 421 | noise (also in baseline) | | 4 | WARN | 14 | - | cache miss for key 'cart:...' | noise (also in baseline) | | 5 | WARN | 3 | - | connection pool at 85 to 97 percent | watch (also in baseline) | ## Timeline - 10:09:00 first payment authorization timeout and first failed checkout, in the same second - 10:09 peak minute: 15 timeouts per minute - 10:10:56 last payment timeout; no further payment errors until the end of the log at 10:14:48 ## Root cause candidates 1. **Payment provider psp-eu slow or unavailable** - evidence: 30 timeouts after exactly 5000 ms, all for provider=psp-eu, none in the baseline; stack traces end in `PaymentClient.authorize`. Confidence: medium. Next check: psp-eu status page and our outbound latency dashboard for 10:08 to 10:12 UTC. ## Symptoms and side effects - "checkout failed for session" is caused by candidate 1: same start second, and its trace ends in `PaymentClient.authorize` via `OrderController.submit`. - Retries (attempt=2 and 3 in the samples) may have added load during the spike. ## Background noise (also in baseline) - SMTP 421 receipt failures (3 in 15 minutes) and cache misses appear yesterday at a similar rate. - Connection pool warnings at 85 to 97 percent also appear yesterday; not the incident, but close to the limit. ## Recommended next steps 1. Confirm with the provider status page; if confirmed, no rollback is needed. 2. Count orders that failed between 10:09 and 10:11 and decide whether to email those customers. 3. Follow-up: alert on payment timeouts above 5 per minute, cap retries with backoff, and look at the connection pool headroom. ## Gaps - No provider-side logs or metrics; the 5000 ms timeout hides how slow the provider really was. FILE:scripts/cluster_logs.py #!/usr/bin/env python3 """Group log lines into error patterns (templates) and rank them for triage. Usage: python3 cluster_logs.py app.log [more.log ...] [options] cat app.log | python3 cluster_logs.py - [options] Options: --min-level LEVEL lowest level to include: DEBUG, INFO, WARN, ERROR (default WARN) --top N show the N largest patterns (default 15) --baseline FILE log from a known-good period; patterns not seen there are marked NEW --json print machine-readable JSON instead of a table Understands plain lines with an ISO-8601, syslog ("Oct 09 10:01:02") or nginx ("[09/Oct/2026:10:01:02 +0300]") timestamp, and JSON lines with level/msg/message/time/timestamp keys, and web server access logs (method, path and status are kept; 5xx counts as ERROR, 4xx other than 404 as WARN). Indented lines, "Traceback", "at ...", "Caused by" and bare "pkg.SomeException: ..." lines are attached to the entry above them. Lines without an explicit level are rated by wording ("failed", "out of memory", "timed out" -> ERROR; "retrying", "deprecated" -> WARN). Variable parts (UUIDs, hex ids, IPs, emails, numbers, quoted values, URL query strings) are masked so repeats of the same problem group together. Exit code: 0 no ERROR-level patterns, 1 ERROR or worse found, 2 usage/input error. Standard library only. """ import json import re import statistics import sys from collections import OrderedDict from datetime import datetime LEVELS = {"TRACE": 0, "DEBUG": 0, "INFO": 1, "NOTICE": 1, "WARN": 2, "WARNING": 2, "ERROR": 3, "ERR": 3, "SEVERE": 3, "CRITICAL": 4, "CRIT": 4, "FATAL": 4, "PANIC": 4, "ALERT": 4, "EMERG": 4} CANON = {0: "DEBUG", 1: "INFO", 2: "WARN", 3: "ERROR", 4: "FATAL"} MONTHS = {m: i for i, m in enumerate(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], 1)} TS_ISO = re.compile(r"(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2}:\d{2})(?:[.,]\d+)?(?:Z|[+-]\d{2}:?\d{2})?") TS_SYSLOG = re.compile(r"\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(\d{1,2}) (\d{2}:\d{2}:\d{2})") TS_NGINX = re.compile(r"\[(\d{2})/(\w{3})/(\d{4}):(\d{2}:\d{2}:\d{2})[^\]]*\]") LEVEL_RE = re.compile(r"(?<![\w-])(TRACE|DEBUG|INFO|NOTICE|WARNING|WARN|ERROR|ERR|SEVERE|CRITICAL|CRIT|FATAL|PANIC)(?![\w-])", re.I) ERROR_HINT = re.compile(r"\b(out of memory|oom-?kill\w*|killed process|segfault|panic|fatal|failed|failure|" r"exception|refused|timed out|timeout|denied|unreachable|code=killed)\b", re.I) WARN_HINT = re.compile(r"\b(deprecated|retrying|retry|slow|degraded|throttl\w*)\b", re.I) ACCESS_RE = re.compile(r'"(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS) (\S+) HTTP/[\d.]+" (\d{3}) ') CONT_RE = re.compile(r"^(\s+\S|Traceback \(most recent call last\)|Caused by:|\s*at [\w$.<>]+\(|\s*\.\.\. \d+ more|[\w$]+(?:\.[\w$]+)+(?:Exception|Error)(?::|$))") MASKS = [ (re.compile(r"\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b", re.I), "<uuid>"), (re.compile(r"\b[\w.+-]+@[\w-]+\.[\w.-]+\b"), "<email>"), (re.compile(r"\b\d{1,3}(?:\.\d{1,3}){3}(?::\d+)?\b"), "<ip>"), (re.compile(r"\b0x[0-9a-f]+\b", re.I), "<hex>"), (re.compile(r"\b(?=[0-9a-f]*\d)(?=[0-9a-f]*[a-f])[0-9a-f]{12,}\b", re.I), "<hex>"), (re.compile(r"\?[^\s\"']+"), "?<query>"), (re.compile(r"\"[^\"]{0,200}\"|'[^']{0,200}'"), "<str>"), (re.compile(r"(?<![\w<])[-+]?\d+(?:\.\d+)?(?:ms|s|kb|mb|gb|%)?(?![\w>])", re.I), "<n>"), ] def usage(msg): print(f"error: {msg}\n", file=sys.stderr) print(__doc__.strip().split("\n\n")[1], file=sys.stderr) sys.exit(2) def parse_time(line): m = TS_ISO.search(line) if m: return datetime.strptime(f"{m.group(1)} {m.group(2)}", "%Y-%m-%d %H:%M:%S"), m.span() m = TS_NGINX.search(line) if m and m.group(2) in MONTHS: d = datetime(int(m.group(3)), MONTHS[m.group(2)], int(m.group(1))) h, mi, s = map(int, m.group(4).split(":")) return d.replace(hour=h, minute=mi, second=s), m.span() m = TS_SYSLOG.search(line) if m: h, mi, s = map(int, m.group(3).split(":")) return datetime(1900, MONTHS[m.group(1)], int(m.group(2)), h, mi, s), m.span() return None, None def parse_line(line): """Return (time, level_num, message) for the first line of an entry.""" s = line.strip() if s.startswith("{"): try: obj = json.loads(s) except ValueError: obj = None if isinstance(obj, dict): lvl = str(obj.get("level") or obj.get("severity") or obj.get("lvl") or "INFO").upper() msg = str(obj.get("msg") or obj.get("message") or obj.get("error") or s) if obj.get("error") and obj.get("error") != msg: msg += f" error={obj['error']}" ts = str(obj.get("time") or obj.get("timestamp") or obj.get("ts") or "") t, _ = parse_time(ts) return t, LEVELS.get(lvl, 1), msg t, span = parse_time(s) rest = s[span[1]:] if span else s acc = ACCESS_RE.search(rest) if acc: # web server access log: keep method, path and status, level from status method, path, status = acc.group(1), acc.group(2).split("?")[0], acc.group(3) lvl = 3 if status.startswith("5") else 2 if status.startswith("4") and status != "404" else 1 return t, lvl, f"{method} {path} -> HTTP{status}" if span and TS_SYSLOG.match(s[span[0]:span[1]]): rest = rest.split(None, 1)[1] if len(rest.split(None, 1)) == 2 else rest # drop syslog hostname m = LEVEL_RE.search(rest[:80]) if m: lvl = LEVELS[m.group(1).upper()] rest = rest[:m.start()] + rest[m.end():] elif ERROR_HINT.search(rest): lvl = 3 # no explicit level, but the wording describes a failure elif WARN_HINT.search(rest): lvl = 2 else: lvl = 1 rest = re.sub(r":\s*:", ":", re.sub(r"^[\s:|-]+", "", rest)) return t, lvl, rest def template(msg): first = msg.split("\n", 1)[0] first = re.sub(r"\[[\w.:/-]*\d[\w.:/-]*\]", "[<id>]", first) # [thread-12], [req-ab12] for rx, repl in MASKS: first = rx.sub(repl, first) return re.sub(r"\s+", " ", first).strip()[:160] def read_entries(paths): entries = [] for p in paths: try: fh = sys.stdin if p == "-" else open(p, encoding="utf-8", errors="replace") except OSError as e: usage(str(e)) with fh: for raw in fh: line = raw.rstrip("\n") if not line.strip(): continue if entries and CONT_RE.match(line): entries[-1]["extra"] += 1 entries[-1]["trace_tail"] = line.strip() continue t, lvl, msg = parse_line(line) entries.append({"time": t, "level": lvl, "msg": msg, "extra": 0, "trace_tail": ""}) return entries def cluster(entries, min_level): groups = OrderedDict() for e in entries: if e["level"] < min_level: continue key = template(e["msg"]) g = groups.setdefault(key, {"template": key, "count": 0, "level": 0, "first": None, "last": None, "sample": e["msg"].split("\n", 1)[0][:200], "trace_tail": "", "minutes": {}}) g["count"] += 1 g["level"] = max(g["level"], e["level"]) if e["trace_tail"] and not g["trace_tail"]: g["trace_tail"] = e["trace_tail"][:160] if e["time"]: g["first"] = min(g["first"] or e["time"], e["time"]) g["last"] = max(g["last"] or e["time"], e["time"]) k = e["time"].strftime("%Y-%m-%d %H:%M") g["minutes"][k] = g["minutes"].get(k, 0) + 1 return list(groups.values()) def spike(g, all_minutes): """Peak minute vs median of this pattern's per-minute counts over the whole time range.""" if g["count"] < 5 or len(all_minutes) < 3: return None series = [g["minutes"].get(m, 0) for m in all_minutes] peak = max(series) med = statistics.median(series) if peak >= 5 and peak >= 3 * max(med, 1): at = all_minutes[series.index(peak)] return f"{peak}/min at {at[11:]} (median {med:g}/min)" return None def fmt(t): return t.strftime("%m-%d %H:%M:%S") if t and t.year != 1900 else (t.strftime("%b %d %H:%M:%S") if t else "-") def main(argv): args, paths = {"min": "WARN", "top": 15, "baseline": None, "json": False}, [] it = iter(argv) for a in it: if a == "--min-level": args["min"] = next(it, "").upper() elif a == "--top": v = next(it, "") if not v.isdigit(): usage("--top needs a number") args["top"] = int(v) elif a == "--baseline": args["baseline"] = next(it, None) elif a == "--json": args["json"] = True elif a.startswith("--"): usage(f"unknown option {a}") else: paths.append(a) if not paths: usage("give at least one log file, or - for stdin") if args["min"] not in LEVELS: usage(f"unknown level {args['min']}") min_level = LEVELS[args["min"]] entries = read_entries(paths) if not entries: print("error: no log lines found", file=sys.stderr) return 2 groups = cluster(entries, min_level) known = None if args["baseline"]: known = {g["template"] for g in cluster(read_entries([args["baseline"]]), 0)} times = sorted(e["time"] for e in entries if e["time"]) all_minutes = [] if times: cur = times[0].replace(second=0) while cur <= times[-1] and len(all_minutes) < 10000: all_minutes.append(cur.strftime("%Y-%m-%d %H:%M")) cur = cur.fromtimestamp(cur.timestamp() + 60) for g in groups: g["new"] = known is not None and g["template"] not in known g["spike"] = spike(g, all_minutes) groups.sort(key=lambda g: (-g["level"], -g["count"])) shown = groups[: args["top"]] total = sum(g["count"] for g in groups) worst = max((g["level"] for g in groups), default=0) if args["json"]: out = {"entries_read": len(entries), "entries_at_or_above_min_level": total, "patterns": len(groups), "time_range": [fmt(times[0]), fmt(times[-1])] if times else None, "patterns_top": [{"level": CANON[g["level"]], "count": g["count"], "share_pct": round(100 * g["count"] / total, 1), "first": fmt(g["first"]), "last": fmt(g["last"]), "new": g["new"], "spike": g["spike"], "template": g["template"], "sample": g["sample"], "trace_tail": g["trace_tail"]} for g in shown]} print(json.dumps(out, indent=2)) return 1 if worst >= 3 else 0 unparsed = sum(1 for e in entries if e["time"] is None) print(f"Read {len(entries)} entries ({unparsed} without a timestamp); " f"{total} at {args['min']} or above in {len(groups)} patterns.") if times: print(f"Time range: {fmt(times[0])} -> {fmt(times[-1])}") if not groups: print("No entries at or above the minimum level.") return 0 print() print(f"{'#':>2} {'LEVEL':<5} {'COUNT':>5} {'SHARE':>6} {'FIRST':<14} {'LAST':<14} FLAGS TEMPLATE") for i, g in enumerate(shown, 1): flags = ",".join(f for f in ("NEW" if g["new"] else "", "SPIKE" if g["spike"] else "") if f) or "-" print(f"{i:>2} {CANON[g['level']]:<5} {g['count']:>5} {100 * g['count'] / total:>5.1f}% " f"{fmt(g['first']):<14} {fmt(g['last']):<14} {flags:<10} {g['template']}") print("\nDetails:") for i, g in enumerate(shown, 1): print(f"{i:>2}. sample: {g['sample']}") if g["trace_tail"]: print(f" trace ends: {g['trace_tail']}") if g["spike"]: print(f" spike: {g['spike']}") if len(groups) > len(shown): print(f"\n({len(groups) - len(shown)} smaller patterns not shown; use --top)") return 1 if worst >= 3 else 0 if __name__ == "__main__": sys.exit(main(sys.argv[1:]))

Running Training Plan Load Checker

--- name: running-plan-load-checker description: Builds and reviews running training plans for 5K, 10K, half marathon, and marathon goals - checks weekly volume jumps, long run share and progression, hard days and back-to-back hard sessions, rest and cutback weeks, peak timing, and taper with a tested script, then explains the risks in plain language and proposes a safer week-by-week plan. Use when a runner shares a plan or asks "is this plan too much?", "build me a 12-week half marathon plan", or "how should I increase my mileage?". --- # Running Plan Load Checker You help everyday runners reach race day healthy. You build plans that progress gradually, and you review existing plans for the load mistakes that cause most overuse injuries: doing too much, too soon, with too little recovery. You are a coach's assistant, not a doctor. Pain, illness, and medical conditions go to a professional (see `references/safety-and-red-flags.md`). ## Files in this skill - `scripts/check_plan.py` - parses a plan table (Markdown or CSV) and checks load progression week by week (Python 3 standard library only) - `references/training-principles.md` - progression, intensity balance, long runs, cutback weeks, peak and taper - `references/safety-and-red-flags.md` - when to stop, see a professional, or adjust the plan - `templates/training-plan.md` - the plan table format the script reads, plus the review layout - `examples/example-half-marathon-review.md` - a draft plan reviewed and fixed ## Workflow ### 1. Get the runner's context Ask for or confirm, in one short message: - Goal race, distance, and date (or number of weeks available). - Current running: weekly km over the last 4 weeks, runs per week, longest recent run. - Experience level and injury history in the last year. - Days available, and any day that must stay free. - Goal: finish comfortably, or a time target. If the runner has a health condition, is returning from injury, is pregnant, or is new to exercise, recommend checking with a doctor before following any plan. ### 2. Put the plan into the table format Use `templates/training-plan.md`: one row per session with `week`, `day`, `type`, and `km`. Use type words the script knows (easy, recovery, long, tempo, intervals, hills, fartlek, race, cross, strength, rest). ### 3. Run the checker ```bash python3 scripts/check_plan.py plan.md --race half --level intermediate --current-km 20 python3 scripts/check_plan.py plan.csv --race marathon --level beginner --current-km 30 --json ``` The weekly table shows km, runs, non-running days, long run, long run share, hard days, and the change versus the highest of the previous three weeks. Findings are HIGH (fix before using the plan) or WARN (review and justify). Exit code 1 means at least one HIGH finding. If you cannot run the script, apply the same checks by hand using `references/training-principles.md` and say so. ### 4. Fix and explain For each finding, change the plan rather than only describing the problem: smooth jumps, insert cutback weeks, move hard sessions apart, shift the peak, and shorten race week. Run the checker again until there are no HIGH findings, and keep any remaining WARN only with a reason (for example an experienced runner returning to a familiar volume). ### 5. Report Use the review layout in `templates/training-plan.md`, as in `examples/example-half-marathon-review.md`: what changed and why, the final plan, how to adjust when life happens, and the safety notes. ## Rules - Distances in km unless the runner uses miles; never mix units in one plan. - Most running should feel easy (conversational). Describe intensity by effort and talk test, not only by pace. - Do not prescribe diets, supplements, or medication. - Never tell a runner to train through sharp, worsening, or limping pain. - A missed week is normal: repeat the previous week instead of jumping ahead. FILE:references/training-principles.md # Training principles used by the checker These are conservative rules of thumb for recreational runners. They are guidelines for spotting risk, not laws; experienced runners can justify exceptions. ## Weekly volume progression - Compare each week with the **highest of the previous three weeks**, not only the week before, so returning to the volume you had before a cutback week is not penalized. - Typical safe increase: up to about 10 percent for beginners, 12 percent for intermediate runners, 15 percent for advanced runners. The script warns above these and rates jumps above 25, 30, or 35 percent as HIGH. - Small absolute changes (3 km or less) are ignored, because 10 percent of a 15 km week is too small to matter. - Week 1 should start close to what the runner already does. Starting far above current volume is the most common plan mistake. ## Cutback weeks - Every 3 to 4 weeks of building, reduce volume by about 20 to 30 percent for one week and shorten the long run. - The script warns after five building weeks in a row without a drop of at least 15 percent (taper weeks excluded). ## Long runs - The long run builds endurance, but it should not dominate the week. Share limits used: 50 percent of weekly km under 30 km per week, 45 percent under 60 km, 40 percent above. Race week is excluded. - Increase the long run by about 1 to 3 km at a time. The script warns when it grows by more than 3 km and more than 20 percent over the previous best. - Minimum longest run before race week: 6 km for 5K, 10 km for 10K, 16 km for a half marathon, 28 km for a marathon (beginner marathon plans often peak at 30 to 32 km). ## Intensity balance - About 80 percent of running time easy, 20 percent moderate or hard. - Hard sessions: tempo or threshold, intervals, hills, fartlek, progression runs, races. Maximum hard days per week used: beginner 1, intermediate 2, advanced 3. - Do not put hard sessions or a hard session and the long run on consecutive days unless the runner is experienced and it is deliberate (the script warns). - Strides (short relaxed accelerations) after an easy run count as easy. ## Rest - Beginners and intermediates need at least one non-running day per week; two or three is normal for 3 to 4 run plans. Cross-training and strength work count as non-running days in the table. ## Peak and taper - Half marathon and marathon: the biggest week should come 2 to 3 weeks before race week (the script flags a peak in the last two weeks as HIGH). - Taper: reduce volume gradually over the last 1 to 3 weeks while keeping some short, sharp running. In race week, aim for about 40 to 60 percent of peak volume besides the race itself (the script warns above 60 percent). ## Units - 1 mile = 1.609 km. Convert a whole plan before checking; the script reads only kilometers. FILE:references/safety-and-red-flags.md # Safety and red flags Use this list whenever you build or review a plan. When in doubt, recommend that the runner sees a doctor, physiotherapist, or sports medicine professional. Do not diagnose. ## Stop running and get medical help right away - Chest pain, pressure, or tightness; fainting or near fainting; unusual shortness of breath; a racing or irregular heartbeat. - Signs of heat illness: confusion, stopping sweating, nausea or vomiting, a very high body temperature. ## Stop the session and rest, then get checked if it persists - Pain that is sharp, localized to one spot on a bone, or makes you limp. - Pain that gets worse as you run, or is worse the next morning. - Swelling, numbness, or pain at night. - Pain that lasts more than a few days of rest. ## Reduce or adjust the plan - Feeling unusually tired for more than a few days, poor sleep, irritability, or a resting heart rate clearly higher than normal: take extra easy days. - Mild illness above the neck (runny nose): easy running may be fine; illness below the neck (fever, chest congestion, stomach bug) or a fever: rest. - Missed one week: repeat the last completed week. Missed two weeks or more: drop back two weeks of volume. - Heat, altitude, and hills: run by effort, not pace, and shorten sessions on very hot days. ## Ask for a medical check before starting a plan - New to exercise, returning after a long break, or over 40 and previously inactive. - Known heart, lung, or metabolic conditions, or a family history of sudden cardiac problems. - Pregnancy or recent childbirth. - A recent injury, especially a bone stress injury. ## Fueling and hydration (general only) - For runs longer than about 75 to 90 minutes, practice carrying water and some carbohydrate during training, not for the first time on race day. - Specific nutrition, supplement, or weight advice belongs to a registered dietitian or doctor. ## How to say it Be clear and kind: "That kind of pain is a reason to stop and get it checked before the next run. The plan will wait; we can adjust the weeks afterward." FILE:templates/training-plan.md # Training plan table (input for scripts/check_plan.py) One row per session. Rest days can be listed with type `rest` and km `0`, or left out. | week | day | type | km | notes | |---|---|---|---|---| | 1 | Tue | easy | 5 | conversational pace | | 1 | Thu | tempo | 6 | 2x8 min comfortably hard, 2 min jog between | | 1 | Sat | long | 10 | easy, practice drinking | | 1 | Sun | cross | 0 | bike or swim 30 to 45 min, optional | Columns: - `week`: 1, 2, 3 ... - `day`: Mon to Sun (or 1 to 7) - `type`: easy, recovery, long, tempo, threshold, intervals, hills, fartlek, progression, race, cross, strength, rest - `km`: distance in kilometers (0 for rest, cross, strength) - `notes`: optional; the workout details Run: `python3 scripts/check_plan.py plan.md --race <5k|10k|half|marathon> --level <beginner|intermediate|advanced> --current-km <km>` --- # Plan review: <runner> - <race> on <date> **Runner:** <current km/week, runs/week, longest recent run, level, injury history> **Goal:** <finish / time target> **Weeks:** <n> **Days available:** <days> ## Checker result (before) <HIGH and WARN findings, short> ## What I changed and why 1. <change> - fixes <finding>; <one-line reason> ## Final plan <table in the format above> ## Checker result (after) <"0 findings" or remaining WARN with the reason it is acceptable> ## How to adjust when life happens - Missed a run: <rule> - Missed a week: <rule> - Feeling run down: <rule> ## Safety notes - <relevant points from references/safety-and-red-flags.md> FILE:examples/example-half-marathon-review.md # Example: reviewing a 10-week half marathon draft **Runner:** "I run about 20 km a week, 3 runs, longest run 9 km. I found this 10-week half marathon plan online. Is it OK?" Intermediate, no injuries in the last year, goal is to finish strong. Available Tue, Wed, Thu, Sat, Sun. **Draft plan (summary):** weeks 1 to 9 build from 24 to 44 km with a long run growing 12 -> 20 km by 1 km per week, tempo or intervals every week (plus extra intervals in week 2 and hills in week 6), no cutback weeks, race on Sunday of week 10. **Command:** ```bash python3 scripts/check_plan.py draft.md --race half --level intermediate --current-km 20 ``` **Output:** ``` WEEK KM RUNS REST LONG LONG% HARD CHANGE 1 24 3 4 12 50% 1 - 2 31 4 3 13 42% 2 +29% 3 28 3 4 14 50% 1 -10% 4 34 4 3 15 44% 1 +10% 5 37 4 3 16 43% 1 +9% 6 39 4 3 17 44% 2 +5% 7 40 4 3 18 45% 1 +3% 8 42 4 3 19 45% 1 +5% 9 44 4 3 20 45% 1 +5% 10 40.1 4 3 21.1 53% 2 -9% Findings: 6 [HIGH] week 9: peak volume (44 km) falls in week 9, too close to race week 10; peak 2 to 3 weeks out [WARN] week 1: week 1 is 24 km versus current 20 km/week [WARN] week 2: volume 31 km is 29% above the recent max of 24 km (aim for 12% or less) [WARN] week 2: hard or long sessions on back-to-back days: 3-4 [WARN] week 5: five weeks in a row without a cutback week (drop volume 20 to 30% every 3 to 4 weeks) [WARN] week 6: hard or long sessions on back-to-back days: 4-5, 5-6 ``` --- # Plan review: half marathon in 12 weeks **Runner:** 20 km/week, 3 runs, longest recent run 9 km, intermediate, no recent injuries **Goal:** finish strong **Weeks:** 12 (race moved to week 12 by starting two weeks earlier) **Days available:** Tue, Wed, Thu, Sat, Sun ## Checker result (before) 1 HIGH (peak in the week before the race, so no taper) and 5 WARN (start too high, a 29 percent jump in week 2, back-to-back hard days in weeks 2 and 6, no cutback week). ## What I changed and why 1. Start at 21 km in week 1 - close to the current 20 km, so the body is not shocked in week 1. 2. Grow about 2 km per week (6 to 10 percent) - removes the week 2 jump. 3. Cutback weeks in weeks 4 and 8 (about 20 percent less, long run back to 10 km) - lets the body absorb the training. 4. One quality session per week on Thursday, never the day before or after the long run - fixes the back-to-back hard days. 5. Peak (36 km, long run 16 km) in week 10, then a taper week (26 km) and a light race week - the race is run fresh. 6. A fourth short easy run on Wednesday from week 2 - adds volume without making the long run heavier. ## Final plan | week | km | Tue | Wed | Thu | Sat | Sun | |---|---|---|---|---|---|---| | 1 | 21 | easy 5 | - | easy 6 + strides | long 10 | - | | 2 | 23 | easy 5 | easy 3 | tempo 5 (2x8 min) | long 10 | - | | 3 | 25 | easy 6 | easy 3 | tempo 5 (2x10 min) | long 11 | - | | 4 | 20 | easy 5 | - | easy 5 | long 10 | - | | 5 | 27 | easy 6 | easy 4 | intervals 6 (5x1 km) | long 11 | - | | 6 | 29 | easy 6 | easy 4 | tempo 7 (3x10 min) | long 12 | - | | 7 | 31 | easy 6 | easy 5 | intervals 7 (6x1 km) | long 13 | - | | 8 | 25 | easy 6 | easy 4 | easy 5 | long 10 | - | | 9 | 34 | easy 7 | easy 5 | tempo 7 (2x15 min) | long 15 | - | | 10 | 36 | easy 7 | easy 6 | intervals 7 (5x1.6 km) | long 16 | - | | 11 | 26 | easy 6 | easy 4 | tempo 5 (20 min at goal pace) | long 11 | - | | 12 | 30.1 | easy 5 + strides | - | easy 4 | - | RACE 21.1 | Week 5 also has an optional 40-minute bike ride on Monday. ## Checker result (after) `python3 scripts/check_plan.py revised.md --race half --level intermediate --current-km 20` -> `Findings: 0`, exit code 0. ## How to adjust when life happens - Missed a run: skip it; do not squeeze it into the next day. - Missed a week: repeat the last week you completed, then continue. - Feeling run down or sore for more than two days: replace the quality session with an easy run or rest. ## Safety notes - Stop and get checked for sharp, one-spot, or limping pain, or pain that is worse the next morning. - Practice drinking (and a small carbohydrate snack) on long runs from week 9, so race day holds no surprises. FILE:scripts/check_plan.py #!/usr/bin/env python3 """Check a running training plan for risky load jumps and missing structure. Usage: python3 check_plan.py plan.md [--race 5k|10k|half|marathon] [--level beginner|intermediate|advanced] [--current-km 20] [--json] python3 check_plan.py plan.csv ... cat plan.md | python3 check_plan.py - ... The plan is a Markdown table or CSV with a header row containing at least week, day, type and km (also accepted: distance, dist). Optional columns are ignored. One row per session; rest days may be listed or left out. day: Mon..Sun, Monday..Sunday or 1..7 type: easy, recovery, long, tempo, threshold, intervals, hills, fartlek, progression, race, cross, strength, rest (anything else counts as easy) km: number (use 0 for rest, cross and strength) Checks per week: volume increase versus the highest of the previous three weeks, long run share of the week (limit 50% under 30 km, 45% under 60 km, 40% above; race week excluded), long run jumps, number of hard days, hard or long sessions on back-to-back days, rest days, and cutback weeks. Plan-level checks: first week versus current weekly volume, longest run versus the race distance, peak week too close to race day, and taper. Exit code: 0 no HIGH findings, 1 at least one HIGH finding, 2 usage or input error. Standard library only. """ import csv import io import json import re import sys DAYS = {"mon": 1, "tue": 2, "wed": 3, "thu": 4, "fri": 5, "sat": 6, "sun": 7} HARD = {"tempo", "threshold", "intervals", "interval", "hills", "hill", "fartlek", "progression", "race", "speed", "track"} NON_RUN = {"rest", "cross", "strength", "off", "yoga", "bike", "swim"} RACE_KM = {"5k": 5.0, "10k": 10.0, "half": 21.1, "marathon": 42.2} MIN_LONG = {"5k": 6, "10k": 10, "half": 16, "marathon": 28} LIMITS = { # weekly increase warn, weekly increase high, max hard days "beginner": (0.10, 0.25, 1), "intermediate": (0.12, 0.30, 2), "advanced": (0.15, 0.35, 3), } def long_share_limit(week_km): """Low-volume weeks naturally have a bigger long-run share.""" return 0.50 if week_km < 30 else 0.45 if week_km < 60 else 0.40 def usage(msg): print(f"error: {msg}\n", file=sys.stderr) print(__doc__.strip().split("\n\n")[1], file=sys.stderr) sys.exit(2) def read_rows(text): lines = [ln for ln in text.splitlines() if ln.strip()] if not lines: return [] if lines[0].lstrip().startswith("|") or sum(ln.count("|") >= 3 for ln in lines) > len(lines) / 2: rows = [] for ln in lines: if "|" not in ln or re.match(r"^\s*\|?\s*:?-{2,}", ln): continue rows.append([c.strip() for c in ln.strip().strip("|").split("|")]) else: rows = list(csv.reader(io.StringIO("\n".join(lines)))) header = [h.strip().lower() for h in rows[0]] out = [] for r in rows[1:]: out.append({header[i]: (r[i].strip() if i < len(r) else "") for i in range(len(header))}) return out def num(value): m = re.search(r"\d+(?:[.,]\d+)?", value or "") return float(m.group(0).replace(",", ".")) if m else 0.0 def parse(rows): if not rows: raise ValueError("no table rows found") keys = rows[0].keys() kcol = next((k for k in ("km", "distance", "dist", "distance_km") if k in keys), None) for need, col in (("week", "week" in keys), ("day", "day" in keys), ("type", "type" in keys), ("km", kcol)): if not col: raise ValueError(f"missing column '{need}' (found: {', '.join(keys)})") sessions = [] for i, r in enumerate(rows, 2): w = num(r["week"]) d = r["day"].strip().lower() day = DAYS.get(d[:3]) if d[:3] in DAYS else (int(d) if d.isdigit() and 1 <= int(d) <= 7 else None) if not w or day is None: raise ValueError(f"row {i}: cannot read week/day from {r['week']!r}/{r['day']!r}") t = (r["type"].strip().lower().split() or ["easy"])[0] km = num(r[kcol]) sessions.append({"week": int(w), "day": day, "type": t, "km": 0.0 if t in NON_RUN else km}) return sessions def analyze(sessions, race, level, current_km): warn_up, high_up, max_hard = LIMITS[level] weeks = {} for s in sessions: weeks.setdefault(s["week"], []).append(s) findings, table = [], [] def add(sev, week, msg): findings.append({"severity": sev, "week": week, "message": msg}) prev_long = [] week_nums = sorted(weeks) for idx, w in enumerate(week_nums): ss = sorted(weeks[w], key=lambda s: s["day"]) runs = [s for s in ss if s["km"] > 0] total = round(sum(s["km"] for s in runs), 1) run_days = sorted({s["day"] for s in runs}) longest = max((s["km"] for s in runs), default=0.0) hard_days = sorted({s["day"] for s in runs if s["type"] in HARD}) stress_days = sorted({s["day"] for s in runs if s["type"] in HARD or s["type"] == "long"}) ref = max((r["km"] for r in table[-3:]), default=None) change = None if not ref else (total - ref) / ref row = {"week": w, "km": total, "runs": len(runs), "rest_days": 7 - len(run_days), "long_km": longest, "long_share": round(longest / total, 2) if total else 0.0, "hard_days": len(hard_days), "change_vs_recent_max": None if change is None else round(change * 100)} table.append(row) if change is not None and total - ref > 3: if change > high_up: add("HIGH", w, f"volume {total:g} km is {change:.0%} above the recent max of {ref:g} km (limit {high_up:.0%})") elif change > warn_up: add("WARN", w, f"volume {total:g} km is {change:.0%} above the recent max of {ref:g} km (aim for {warn_up:.0%} or less)") is_race_week = bool(race) and idx == len(week_nums) - 1 long_share = long_share_limit(total) share = round(longest / total, 2) if total else 0.0 if total >= 15 and not is_race_week and share > long_share: sev = "HIGH" if share > long_share + 0.15 else "WARN" add(sev, w, f"long run {longest:g} km is {share:.0%} of the week's {total:g} km (aim for {long_share:.0%} or less)") if prev_long and longest > max(prev_long) + 3 and longest > max(prev_long) * 1.2 and not is_race_week: add("WARN", w, f"longest run jumps to {longest:g} km from a previous best of {max(prev_long):g} km (add 1 to 3 km at a time)") prev_long.append(longest) if len(hard_days) > max_hard: add("WARN", w, f"{len(hard_days)} hard days (days {', '.join(map(str, hard_days))}); {level} plans usually have at most {max_hard}") b2b = [(a, b) for a, b in zip(stress_days, stress_days[1:]) if b - a == 1] if b2b: add("WARN", w, "hard or long sessions on back-to-back days: " + ", ".join(f"{a}-{b}" for a, b in b2b)) if len(run_days) == 7 and level != "advanced": add("WARN", w, "no rest day this week") # cutback weeks: in any 5 consecutive weeks of build-up, expect one week at least 15% below the week before build = [r for r in table] if race and len(build) >= 3: build = build[:-2] # leave the taper out streak = 0 for i, r in enumerate(build): if i and build[i - 1]["km"] and r["km"] <= build[i - 1]["km"] * 0.85: streak = 0 else: streak += 1 if streak == 5: add("WARN", r["week"], "five weeks in a row without a cutback week (drop volume 20 to 30% every 3 to 4 weeks)") streak = 0 if current_km is not None and table: first = table[0]["km"] if current_km == 0 and first > 10: add("HIGH", table[0]["week"], f"week 1 starts at {first:g} km from no running; begin with run-walk sessions") elif current_km and (first - current_km) / current_km > high_up and first - current_km > 3: add("HIGH", table[0]["week"], f"week 1 is {first:g} km but current volume is {current_km:g} km/week ({(first - current_km) / current_km:.0%} jump)") elif current_km and (first - current_km) / current_km > warn_up and first - current_km > 3: add("WARN", table[0]["week"], f"week 1 is {first:g} km versus current {current_km:g} km/week") if race and table: peak = max(table, key=lambda r: r["km"]) last = table[-1]["week"] race_rows = [s for s in sessions if s["type"] == "race"] if not race_rows: add("INFO", last, "no session with type 'race'; the last week is treated as race week") build_long = max((r["long_km"] for r in table[:-1]), default=0) if build_long < MIN_LONG[race]: add("HIGH" if race in ("half", "marathon") else "WARN", None, f"longest training run before race week is {build_long:g} km; for a {race} aim for at least {MIN_LONG[race]} km") if len(table) >= 3 and race in ("half", "marathon") and peak["week"] >= last - 1: add("HIGH", peak["week"], f"peak volume ({peak['km']:g} km) falls in week {peak['week']}, too close to race week {last}; peak 2 to 3 weeks out") if len(table) >= 2: race_km = sum(s["km"] for s in sessions if s["type"] == "race") race_week_other = table[-1]["km"] - race_km if peak["km"] and race_week_other > 0.6 * peak["km"]: add("WARN", last, f"race week has {race_week_other:g} km besides the race ({race_week_other / peak['km']:.0%} of peak); taper to about 40 to 60%") return table, findings def main(argv): opts = {"race": None, "level": "intermediate", "current": None, "json": False} paths = [] it = iter(argv) for a in it: if a == "--race": opts["race"] = (next(it, "") or "").lower() if opts["race"] not in RACE_KM: usage("--race must be 5k, 10k, half or marathon") elif a == "--level": opts["level"] = (next(it, "") or "").lower() if opts["level"] not in LIMITS: usage("--level must be beginner, intermediate or advanced") elif a == "--current-km": v = next(it, "") try: opts["current"] = float(v) except ValueError: usage("--current-km needs a number") elif a == "--json": opts["json"] = True elif a.startswith("--"): usage(f"unknown option {a}") else: paths.append(a) if len(paths) != 1: usage("give exactly one plan file, or - for stdin") try: text = sys.stdin.read() if paths[0] == "-" else open(paths[0], encoding="utf-8").read() sessions = parse(read_rows(text)) except (OSError, ValueError) as e: print(f"error: {e}", file=sys.stderr) return 2 table, findings = analyze(sessions, opts["race"], opts["level"], opts["current"]) order = {"HIGH": 0, "WARN": 1, "INFO": 2} findings.sort(key=lambda f: (order[f["severity"]], f["week"] or 0)) if opts["json"]: print(json.dumps({"weeks": table, "findings": findings}, indent=2)) else: print(f"Plan: {len(table)} weeks, {sum(r['km'] for r in table):g} km total | level={opts['level']}" f" race={opts['race'] or '-'} current={opts['current'] if opts['current'] is not None else '-'} km/week") print(f"\n{'WEEK':>4} {'KM':>6} {'RUNS':>4} {'REST':>4} {'LONG':>5} {'LONG%':>5} {'HARD':>4} {'CHANGE':>7}") for r in table: ch = "-" if r["change_vs_recent_max"] is None else f"{r['change_vs_recent_max']:+d}%" print(f"{r['week']:>4} {r['km']:>6g} {r['runs']:>4} {r['rest_days']:>4} {r['long_km']:>5g} " f"{r['long_share']:>5.0%} {r['hard_days']:>4} {ch:>7}") print(f"\nFindings: {len(findings)}") for f in findings: where = f"week {f['week']}" if f["week"] else "plan" print(f" [{f['severity']}] {where}: {f['message']}") if not findings: print(" none - load progression looks reasonable") return 1 if any(f["severity"] == "HIGH" for f in findings) else 0 if __name__ == "__main__": sys.exit(main(sys.argv[1:]))

Menu Food Cost and Pricing Calculator

--- name: menu-food-cost-calculator description: Costs recipes and menu items for cafes, restaurants, bakeries, food trucks, and caterers - converts purchase prices and yields into an exact cost per portion, food cost percentage on the tax-free price, contribution margin, and a suggested price at a target food cost, then classifies items with menu engineering (Star, Plowhorse, Puzzle, Dog) and recommends price, portion, and menu changes. Use when a user asks "what does this dish cost me?", "how should I price my menu?", "why is my food cost so high?", or shares recipes with supplier prices. --- # Menu Food Cost and Pricing Calculator You help small food businesses know what every plate really costs and price it with confidence. You work from real purchase prices and recipes, you show the math, and you think about margin in money, not only in percentages. ## Files in this skill - `scripts/cost_menu.py` - costs every recipe from a JSON costing sheet, suggests prices, and runs menu engineering (Python 3 standard library only) - `references/food-cost-basics.md` - yield, as-purchased versus edible cost, food cost percent, taxes, and common costing mistakes - `references/pricing-strategies.md` - target-percent pricing, margin-based pricing, rounding, and menu engineering actions - `templates/recipe-costing-sheet.md` - the JSON costing sheet the script reads, plus the report layout - `examples/example-cafe-menu.md` - a worked review of a five-item cafe menu ## Workflow ### 1. Collect the inputs Ask for or confirm: - Currency, and whether menu prices include VAT or sales tax (and the rate). - Target food cost percent (typical ranges are in `references/food-cost-basics.md`; default 30). - For each ingredient: purchase price, pack size and unit, and yield (usable share after trimming, peeling, cooking loss, or spoilage). - For each item: recipe quantities as prepared amounts, number of portions per batch, current menu price, packaging or garnish per portion, and weekly sales if known. If something is missing, use a clearly labeled assumption (for example "yield 90 percent assumed for avocados") and list it in the report. ### 2. Build the costing sheet Fill in `templates/recipe-costing-sheet.md` as JSON. Use units the script knows (g, kg, ml, l, oz, lb, each). If an ingredient is bought by the piece but used by weight, weigh one piece and convert; never mix dimensions. ### 3. Run the calculator ```bash python3 scripts/cost_menu.py menu.json python3 scripts/cost_menu.py menu.json --target 28 python3 scripts/cost_menu.py menu.json --json ``` The table shows cost per portion, menu price, net price without tax, food cost percent, contribution margin (net price minus cost), the price at the target food cost (rounded up), and the menu engineering class when weekly sales are given for every item. Errors (unknown ingredients, unit mismatches) and HIGH findings make the exit code 1. If you cannot run the script, do the same calculation by hand, line by line, and say so. ### 4. Recommend Use `references/pricing-strategies.md`: 1. Fix data errors first and rerun. 2. For HIGH and WARN items choose between raising the price, trimming the portion, changing an expensive ingredient, or accepting a higher percent because the money margin is strong. Name the trade-off. 3. Use the menu engineering class to decide where an item belongs on the menu and whether to promote, reprice, rework, or remove it. 4. Rerun with the proposed changes to show the before and after. ### 5. Report Use the report layout in `templates/recipe-costing-sheet.md`, as in `examples/example-cafe-menu.md`. ## Rules - Show the formula for at least one item so the owner can check it: cost per portion / net price x 100. - Never treat the price at target as an instruction to lower an existing price; it is a benchmark. - Do not give tax or legal advice; only apply the tax rate the user provides. - Respect allergens and dietary claims when suggesting substitutions, and never suggest lowering food safety or quality standards. - Recheck costs when supplier prices change by more than about 5 percent. FILE:references/food-cost-basics.md # Food cost basics ## Key terms - **As-purchased (AP) cost**: what you pay for the pack, case, or piece. - **Yield percent**: the usable share after trimming, peeling, deboning, cooking loss, or spoilage. Salmon fillet trimmed of skin and pin bones might yield 85 percent; whole avocados where 1 in 10 is unusable yield 90 percent when counted by the piece. - **Edible portion (EP) cost** = AP cost per unit / (yield percent / 100). Recipes list prepared, usable quantities, so they are costed at EP cost. - **Plate cost (cost per portion)** = sum of ingredient EP costs for the batch / portions + extras per portion (packaging, napkin, garnish, sauce cup). - **Net price** = menu price / (1 + tax rate), when menu prices include VAT or sales tax. Food cost must be measured against the money you keep, not the tax you collect. - **Food cost percent** = plate cost / net price x 100. - **Contribution margin** = net price - plate cost. This is the money each sale leaves to pay labor, rent, and profit. ## Worked formula Salmon fillet bought at 32.00 per kg with 85 percent yield: - AP cost per g = 32.00 / 1000 = 0.032 - EP cost per g = 0.032 / 0.85 = 0.0376 - 160 g portion = 160 x 0.0376 = 6.02 ## Typical food cost targets (rough guide) | Concept | Typical food cost percent | | --- | --- | | Coffee and espresso drinks | 15 to 25 | | Bakery items | 20 to 30 | | Cafe brunch dishes | 28 to 35 | | Casual restaurant mains | 28 to 35 | | Steak and seafood mains | 35 to 45 | | Pizza | 20 to 28 | | Catering trays | 25 to 35 | Your right target depends on labor, rent, and volume. A low-labor item can run a higher food cost percent and still be very profitable. ## Common costing mistakes 1. Forgetting small items: oil, butter for the pan, salt, garnish, sauces, and takeaway packaging. Add them or use extras_per_portion. 2. Using AP cost without yield for proteins and produce. 3. Measuring food cost against prices that include tax. 4. Costing the recipe card instead of what the kitchen actually plates (portion creep). Weigh five real portions. 5. Old supplier prices. Update the sheet when a price moves by about 5 percent or more. 6. Mixing units: an ingredient bought by the piece but used by weight needs one piece weighed. 7. Ignoring waste and staff meals; track them separately and compare actual food cost (from inventory) with this theoretical cost. ## Theoretical versus actual food cost This skill calculates theoretical cost: what food should cost if recipes are followed. Actual food cost = (opening inventory + purchases - closing inventory) / net food sales. A gap of more than about 2 to 3 points usually means waste, portion creep, theft, or wrong prices on the sheet. FILE:references/pricing-strategies.md # Pricing strategies and menu engineering ## Ways to set a price 1. **Target food cost percent**: price = plate cost / target x (1 + tax rate), rounded up. Simple, and the script's "AT TARGET" column. Weak spot: cheap items end up underpriced and expensive proteins overpriced. 2. **Contribution margin**: decide the money each item must earn (for example at least 5.00 for a main), then price = (plate cost + margin) x (1 + tax rate). Better for high-cost proteins. 3. **Market check**: compare with three to five similar places nearby. Price perception matters as much as cost. 4. **Blend**: start from the target price, check the margin in money, then sanity-check against the market. ## Rounding and presentation - Round up to the step your menu uses (0.10, 0.50, or whole numbers). Upscale menus often use whole numbers without currency signs; casual menus often end in .50 or .90. - Avoid many small increases across the whole menu at once; raise the items with the weakest margin first. - Keep price gaps logical: an oat milk upgrade should cover its extra cost (oat drink often costs about twice as much as dairy milk per liter). ## Menu engineering Needs weekly sales for every item. The script uses: - **Popularity line**: an item is popular if it sells at least 70 percent of an equal share (with 5 items, 0.7 x 20 percent = 14 percent of units sold). - **Margin line**: the sales-weighted average contribution margin. | Class | Popularity | Margin | What to do | | --- | --- | --- | --- | | Star | high | high | Keep quality and portion consistent, place it in the best menu spot, small price increases are usually safe. | | Plowhorse | high | low | Raise price a little, trim cost (portion, garnish, supplier), or pair it with a high-margin add-on. Do not remove it. | | Puzzle | low | high | Promote it: better menu placement, a description, staff recommendation, a photo. Check the price is not scaring guests. | | Dog | low | low | Rework the recipe or price, or remove it, unless it serves a purpose (kids menu, dietary option, signature item). | ## Choosing a fix for a high food cost item | Option | Good when | Risk | | --- | --- | --- | | Raise the price | the item is popular and the market allows it | fewer sales if the jump is large | | Trim the portion | portions are larger than guests expect | guests notice; keep value perception | | Swap an ingredient | a cheaper equal-quality option exists | allergen and taste changes; update the menu text | | Accept a higher percent | the money margin is the highest on the menu | needs volume to pay off | | Remove the item | it is a Dog with no strategic role | regulars may miss it | Always rerun the calculator with the proposed change and show before and after. FILE:templates/recipe-costing-sheet.md # Recipe costing sheet (input for scripts/cost_menu.py) Save as `menu.json`. Quantities in recipes are prepared (usable) amounts. ```json { "currency": "EUR", "target_food_cost_pct": 30, "menu_price_includes_tax_pct": 10, "price_rounding": 0.10, "ingredients": [ {"name": "flour", "price": 0.95, "per": "1 kg"}, {"name": "butter", "price": 9.80, "per": "1 kg"}, {"name": "eggs", "price": 3.60, "per": "12 each"}, {"name": "blueberries", "price": 16.00, "per": "1 kg", "yield_pct": 95} ], "recipes": [ { "name": "Blueberry Muffin", "portions": 12, "menu_price": 3.20, "sold_per_week": 90, "extras_per_portion": 0.06, "items": [["flour", "500 g"], ["butter", "180 g"], ["eggs", "3 each"], ["blueberries", "300 g"]] } ] } ``` Field notes: - `per`: the pack you buy, as "<amount> <unit>" (g, kg, mg, ml, cl, dl, l, oz, lb, each). - `yield_pct`: 1 to 100, default 100. - `menu_price_includes_tax_pct`: 0 if menu prices are shown without tax. - `sold_per_week`: give it for every item (or none) to get menu engineering classes. - `extras_per_portion`: packaging, napkins, garnish, sauce cups, in money. Run: `python3 scripts/cost_menu.py menu.json [--target 30] [--json]` --- # Menu costing report: <business> - <date> **Target food cost:** <x>% **Prices include tax:** <rate or no> **Currency:** <code> **Assumptions:** <yields, missing prices, portion weights> ## Results (before) | Item | Cost/portion | Price | Net | Food % | Margin | At target | Class | | --- | --- | --- | --- | --- | --- | --- | --- | ## Formula check <one item worked out line by line> ## What needs attention 1. **<item>** - <finding>. Options: <price / portion / ingredient / accept>. Recommendation: <one>. ## Proposed changes and results (after) <changes, then the new table or the changed rows> ## Menu engineering actions - Stars: <items and action> - Plowhorses: <items and action> - Puzzles: <items and action> - Dogs: <items and action> ## Next steps - <weigh real portions, update supplier prices, track actual food cost monthly> FILE:examples/example-cafe-menu.md # Example: a five-item cafe menu **User:** "We are a small brunch cafe. Prices include 10 percent VAT and I want about 30 percent food cost. Here are my supplier prices and recipes. Why is my margin so thin?" The sheet has 16 ingredients and 5 items with weekly sales (avocado yield 90 percent because about 1 in 10 is unusable; salmon 85 percent after trimming). **Command:** ```bash python3 scripts/cost_menu.py cafe-menu.json ``` **Output (before):** ``` ITEM COST PRICE NET FOOD% MARGIN AT TARGET CLASS Avocado Toast 3.13 9.50 8.64 36.2 5.51 11.50 Star Salmon Spinach Bowl 8.02 14.50 13.18 60.8 5.16 29.50 Puzzle Flat White 0.72 3.80 3.45 21.0 2.73 2.70 Plowhorse Oat Flat White 0.91 4.20 3.82 23.9 2.91 3.40 Plowhorse Blueberry Muffin 0.79 3.20 2.91 27.2 2.12 3.00 Dog Findings (8): [HIGH] Salmon Spinach Bowl: food cost 60.8% is far above the 30% target; price EUR 29.50 or cut cost 4.06 per portion [WARN] Avocado Toast: food cost 36.2% is above the 30% target; price at target would be EUR 11.50 [INFO] Salmon Spinach Bowl: salmon fillet is 76% of the cost; its price or portion matters most [INFO] menu engineering: weighted average margin EUR 3.22, popularity line 14.0% of items sold [INFO] ingredient 'truffle oil' is not used in any recipe ``` --- # Menu costing report: brunch cafe - October **Target food cost:** 30% **Prices include tax:** 10% VAT **Currency:** EUR **Assumptions:** avocado yield 90%, salmon 85%, spinach 90%; extras 0.10 per dish, 0.12 per coffee (cup and lid), 0.06 per muffin. ## Formula check (Salmon Spinach Bowl, before) - Salmon 160 g x (32.00 / 1000 / 0.85) = 6.02 - Spinach 70 g x (14.00 / 1000 / 0.90) = 1.09; egg 0.30; tomatoes 0.36; olive oil 0.15; extras 0.10 - Cost per portion = 8.02; net price = 14.50 / 1.10 = 13.18; food cost = 8.02 / 13.18 x 100 = 60.8% ## What needs attention 1. **Salmon Spinach Bowl (HIGH, Puzzle)** - 60.8% food cost; salmon is 76% of the cost. Pricing it at target (29.50) is unrealistic for a cafe. Recommendation: reduce salmon to 120 g (still a generous portion for a bowl) and raise the price to 17.50; accept about 40% food cost because the margin becomes the highest on the menu. 2. **Avocado Toast (WARN, Star)** - 36.2%. It is the best-selling dish, so a 1.00 increase to 10.50 is low risk. 3. **Flat White and Oat Flat White (Plowhorses)** - healthy percentages (21 to 24%) but small margins; do not discount. Keep the oat surcharge at 0.40: the oat drink costs 0.19 more per cup than milk. 4. **Blueberry Muffin (Dog)** - fine percentage, low margin and low sales. Try a bundle with coffee before removing it. 5. **Truffle oil** is on the sheet but in no recipe: remove it from orders or the sheet. ## Proposed changes and results (after) Avocado Toast 10.50; Salmon Spinach Bowl 120 g salmon at 17.50. Rerun: `python3 scripts/cost_menu.py cafe-menu-revised.json` ``` ITEM COST PRICE NET FOOD% MARGIN AT TARGET CLASS Avocado Toast 3.13 10.50 9.55 32.8 6.42 11.50 Star Salmon Spinach Bowl 6.51 17.50 15.91 40.9 9.40 23.90 Puzzle Flat White 0.72 3.80 3.45 21.0 2.73 2.70 Plowhorse Oat Flat White 0.91 4.20 3.82 23.9 2.91 3.40 Plowhorse Blueberry Muffin 0.79 3.20 2.91 27.2 2.12 3.00 Dog Findings (6): [WARN] Salmon Spinach Bowl: food cost 40.9% is above the 30% target; price at target would be EUR 23.90 [INFO] menu engineering: weighted average margin EUR 3.56, popularity line 14.0% of items sold ``` Exit code 0. The remaining WARN is accepted on purpose: 9.40 margin per bowl versus 5.16 before. ## Menu engineering actions - Stars: Avocado Toast - keep the recipe consistent, top of the brunch section. - Plowhorses: Flat White, Oat Flat White - no discounts; suggest a pastry with every coffee. - Puzzles: Salmon Spinach Bowl - give it a short description and staff recommendation; check sales after 4 weeks at the new price. - Dogs: Blueberry Muffin - test a coffee + muffin bundle for 4 weeks, then decide. ## Next steps - Weigh five real salmon portions this week to confirm the 120 g spec is followed. - Update supplier prices monthly and rerun the sheet. - Compare with actual food cost from inventory at month end. FILE:scripts/cost_menu.py #!/usr/bin/env python3 """Cost menu items from recipes and purchase prices, and suggest menu prices. Usage: python3 cost_menu.py menu.json [--target 30] [--json] cat menu.json | python3 cost_menu.py - Input JSON (see templates/recipe-costing-sheet.md): { "currency": "EUR", "target_food_cost_pct": 30, # optional, default 30 (or --target) "menu_price_includes_tax_pct": 10, # optional; VAT/sales tax included in menu prices "price_rounding": 0.10, # optional; suggested prices round UP to this step "ingredients": [ {"name": "butter", "price": 9.80, "per": "1 kg", "yield_pct": 100} ], "recipes": [ {"name": "Croissant", "portions": 12, "menu_price": 3.20, "sold_per_week": 180, "extras_per_portion": 0.05, # optional: packaging, napkin, garnish "items": [["butter", "600 g"], ["flour", "1 kg"]]} ] } Units: g, kg, mg, ml, cl, dl, l, oz, lb, each (also pc, pcs, piece, unit, egg). Recipe quantities are the prepared (usable) amounts. yield_pct is the usable share of what you buy after trimming, peeling, cooking loss or spoilage. Per recipe: cost per portion, food cost percent of the net (tax-free) menu price, contribution margin, suggested price at the target, and the three biggest cost drivers. With sold_per_week on every recipe, adds a menu engineering class (Star, Plowhorse, Puzzle, Dog). Exit code: 0 ok, 1 errors in the data or HIGH findings, 2 usage or input error. Standard library only. """ import json import math import re import sys UNITS = { # unit -> (dimension, factor to base unit g / ml / each) "mg": ("mass", 0.001), "g": ("mass", 1.0), "kg": ("mass", 1000.0), "oz": ("mass", 28.3495), "lb": ("mass", 453.592), "ml": ("volume", 1.0), "cl": ("volume", 10.0), "dl": ("volume", 100.0), "l": ("volume", 1000.0), "each": ("count", 1.0), "pc": ("count", 1.0), "pcs": ("count", 1.0), "piece": ("count", 1.0), "pieces": ("count", 1.0), "unit": ("count", 1.0), "units": ("count", 1.0), "egg": ("count", 1.0), "eggs": ("count", 1.0), } BASE = {"mass": "g", "volume": "ml", "count": "each"} def usage(msg): print(f"error: {msg}\n", file=sys.stderr) print(__doc__.strip().split("\n\n")[1], file=sys.stderr) sys.exit(2) def parse_qty(text): """'600 g' -> (600.0, 'mass', 600.0 in base units).""" m = re.fullmatch(r"\s*(\d+(?:[.,]\d+)?)\s*([a-zA-Z]+)?\s*", str(text)) if not m: raise ValueError(f"cannot read quantity {text!r}") qty = float(m.group(1).replace(",", ".")) unit = (m.group(2) or "each").lower() if unit not in UNITS: raise ValueError(f"unknown unit {unit!r} in {text!r}") dim, factor = UNITS[unit] return qty, dim, qty * factor def round_up(value, step): return math.ceil(round(value / step, 6)) * step def analyze(data, target_override=None): errors, findings = [], [] cur = data.get("currency", "") target = float(target_override or data.get("target_food_cost_pct", 30)) tax = float(data.get("menu_price_includes_tax_pct", 0)) step = float(data.get("price_rounding", 0.10)) ingredients = {} for ing in data.get("ingredients", []): name = str(ing.get("name", "")).strip().lower() try: _, dim, base_qty = parse_qty(ing["per"]) price = float(ing["price"]) except (KeyError, ValueError, TypeError) as e: errors.append(f"ingredient {name or '?'}: {e}") continue y = float(ing.get("yield_pct", 100)) if not 0 < y <= 100: errors.append(f"ingredient {name}: yield_pct must be between 1 and 100") continue ingredients[name] = {"dim": dim, "cost_per_base": price / base_qty / (y / 100), "yield": y, "used": False} results = [] for rec in data.get("recipes", []): rname = rec.get("name", "?") portions = float(rec.get("portions", 1) or 1) lines, bad = [], False for item in rec.get("items", []): iname, qtext = str(item[0]).strip().lower(), item[1] ing = ingredients.get(iname) if not ing: errors.append(f"{rname}: unknown ingredient {iname!r} (add it to ingredients)") bad = True continue ing["used"] = True try: _, dim, base_qty = parse_qty(qtext) except ValueError as e: errors.append(f"{rname}: {e}") bad = True continue if dim != ing["dim"]: errors.append(f"{rname}: {iname} is bought by {BASE[ing['dim']]} but used by {BASE[dim]} ({qtext}); " f"convert it (for example weigh one piece)") bad = True continue lines.append((iname, base_qty * ing["cost_per_base"])) if bad: continue batch = sum(c for _, c in lines) extras = float(rec.get("extras_per_portion", 0)) cost = batch / portions + extras price = float(rec.get("menu_price", 0)) net = price / (1 + tax / 100) if price else 0.0 pct = 100 * cost / net if net else None suggested = round_up(cost / (target / 100) * (1 + tax / 100), step) drivers = sorted(lines, key=lambda x: -x[1])[:3] r = {"name": rname, "portions": portions, "cost_per_portion": round(cost, 3), "menu_price": price, "net_price": round(net, 2), "food_cost_pct": None if pct is None else round(pct, 1), "contribution_margin": round(net - cost, 2) if net else None, "suggested_price_at_target": round(suggested, 2), "sold_per_week": rec.get("sold_per_week"), "drivers": [{"ingredient": n, "share_pct": round(100 * c / batch, 1) if batch else 0} for n, c in drivers]} results.append(r) if pct is None: findings.append(("WARN", rname, f"no menu_price; suggested {cur} {suggested:.2f} at {target:g}% food cost")) elif pct > target + 15: findings.append(("HIGH", rname, f"food cost {pct:.1f}% is far above the {target:g}% target; " f"price {cur} {suggested:.2f} or cut cost {cost - net * target / 100:.2f} per portion")) elif pct > target + 5: findings.append(("WARN", rname, f"food cost {pct:.1f}% is above the {target:g}% target; " f"price at target would be {cur} {suggested:.2f}")) elif pct < target - 15: findings.append(("INFO", rname, f"food cost only {pct:.1f}%; check the recipe lists every ingredient and portion size")) if drivers and batch and drivers[0][1] / batch > 0.5: findings.append(("INFO", rname, f"{drivers[0][0]} is {100 * drivers[0][1] / batch:.0f}% of the cost; " f"its price or portion matters most")) sold = [r for r in results if isinstance(r["sold_per_week"], (int, float)) and r["contribution_margin"] is not None] if sold and len(sold) == len(results) and len(sold) >= 3: total = sum(r["sold_per_week"] for r in sold) pop_line = 0.7 / len(sold) avg_cm = sum(r["contribution_margin"] * r["sold_per_week"] for r in sold) / total if total else 0 for r in sold: high_pop = total and r["sold_per_week"] / total >= pop_line high_cm = r["contribution_margin"] >= avg_cm r["menu_class"] = {(True, True): "Star", (True, False): "Plowhorse", (False, True): "Puzzle", (False, False): "Dog"}[(bool(high_pop), high_cm)] findings.append(("INFO", None, f"menu engineering: weighted average margin {cur} {avg_cm:.2f}, " f"popularity line {100 * pop_line:.1f}% of items sold")) for name, ing in ingredients.items(): if not ing["used"]: findings.append(("INFO", None, f"ingredient {name!r} is not used in any recipe")) return {"currency": cur, "target_pct": target, "tax_pct": tax, "recipes": results, "errors": errors, "findings": [{"severity": s, "recipe": n, "message": m} for s, n, m in findings]} def main(argv): target, as_json, paths = None, False, [] it = iter(argv) for a in it: if a == "--target": try: target = float(next(it, "")) except ValueError: usage("--target needs a number, for example 30") if not 5 <= target <= 80: usage("--target should be a food cost percent between 5 and 80") elif a == "--json": as_json = True elif a.startswith("--"): usage(f"unknown option {a}") else: paths.append(a) if len(paths) != 1: usage("give exactly one menu JSON file, or - for stdin") try: raw = sys.stdin.read() if paths[0] == "-" else open(paths[0], encoding="utf-8").read() data = json.loads(raw) except (OSError, ValueError) as e: print(f"error: cannot read menu JSON: {e}", file=sys.stderr) return 2 if not data.get("recipes"): print("error: no recipes in the input", file=sys.stderr) return 2 rep = analyze(data, target) if as_json: print(json.dumps(rep, indent=2)) else: cur = rep["currency"] print(f"Target food cost {rep['target_pct']:g}% | prices include {rep['tax_pct']:g}% tax | currency {cur}\n") print(f"{'ITEM':<22} {'COST':>7} {'PRICE':>7} {'NET':>7} {'FOOD%':>6} {'MARGIN':>7} {'AT TARGET':>9} CLASS") for r in rep["recipes"]: pct = "-" if r["food_cost_pct"] is None else f"{r['food_cost_pct']:.1f}" cm = "-" if r["contribution_margin"] is None else f"{r['contribution_margin']:.2f}" print(f"{r['name'][:22]:<22} {r['cost_per_portion']:>7.2f} {r['menu_price']:>7.2f} {r['net_price']:>7.2f} " f"{pct:>6} {cm:>7} {r['suggested_price_at_target']:>9.2f} {r.get('menu_class', '-')}") print("\nTop cost drivers:") for r in rep["recipes"]: print(f" {r['name']}: " + ", ".join(f"{d['ingredient']} {d['share_pct']:g}%" for d in r["drivers"])) if rep["errors"]: print(f"\nErrors ({len(rep['errors'])}):") for e in rep["errors"]: print(f" [ERROR] {e}") print(f"\nFindings ({len(rep['findings'])}):") order = {"HIGH": 0, "WARN": 1, "INFO": 2} for f in sorted(rep["findings"], key=lambda f: order[f["severity"]]): print(f" [{f['severity']}] {f['recipe'] + ': ' if f['recipe'] else ''}{f['message']}") bad = rep["errors"] or any(f["severity"] == "HIGH" for f in rep["findings"]) return 1 if bad else 0 if __name__ == "__main__": sys.exit(main(sys.argv[1:]))

Room Makeover Concept Brief Builder

Act as an interior designer and visualization art director. I will describe a room I want to redesign. You will turn it into a clear design concept with fixed design details, plus two ready-to-use image prompts that show the SAME room from two opposite viewpoints, so the two AI images look like photos of one real space. Room: ${room:small living room in a timber cabin, about 3.5 x 4.5 meters, vaulted ceiling, one large window facing a pine forest} Who uses it and how: ${use:a couple who read, work on a laptop now and then, and host two friends for board games} Style direction: ${style:warm Nordic cabin, calm and natural, a few bold earthy accents} Must keep: ${keep:the small wood-burning stove and the wide-plank floor} Budget level: ${budget:mid-range, mostly new furniture, no structural work} Second view to show: ${second_view:the reverse angle at dusk, looking from the window back toward the entry door, with the stove lit} Please produce: 1. Design concept - Concept name and a two-sentence story of how the room should feel. - Floor plan in words: what stands on each wall (north, east, south, west) and in the center, with approximate sizes and walking clearances. - Palette: 6 named colors (simple names like "sage green") with where each one is used. - Materials and finishes: walls, ceiling, floor, textiles, metals. 2. Fixed design details (the consistency list) A numbered list of 12 to 16 details that must look identical in every image: each piece of furniture with color, material, and shape; the rug; every light fixture; window and door details; plants and signature objects; and their exact positions in the room. Write each one as a short, concrete phrase an image generator can follow (for example "rust-orange leather sling armchair with a black steel frame, angled toward the stove"). 3. Image prompt A: the base view One detailed prompt for an AI image generator: photoreal interior photography of the room from the entry door looking toward the window, in daytime light. Include every fixed detail that is visible from this viewpoint in its correct position (left and right as seen from the camera), the camera height and lens, lighting, mood, and aspect ratio. End with exclusions (no people, no text, no logos, no clutter). 4. Image prompt B: the second view One detailed prompt for the second view, written so it works with a text-only image generator that cannot see image A: restate ALL fixed details again in full words (never "same as before"), swap left and right correctly for the reversed camera direction, describe what is newly visible (for example the wall behind the first camera), and the new lighting and time of day. Keep palette, materials, and style identical. 5. Consistency checklist Ten yes/no checks to compare image B against image A (for example "Is the sofa still sage green boucle with three seat cushions?"). 6. Shopping and practical notes A short list of the key pieces with what to look for when buying (size, material, approximate price tier), and two layout tips for small rooms. Rules: - Keep everything realistic for the stated budget and room size; flag anything that will not fit. - Use plain color names and concrete shapes; avoid vague words like "nice" or "modern" on their own. - No brand names, no real people, no readable text in the images. - If my description is missing something essential, make a sensible assumption and list it at the top.

Nordic Cabin Living Room Concept (Daytime View)

Photoreal interior architectural photograph of a small, warm Nordic cabin living room, about 3.5 by 4.5 meters, shot from the entry door looking straight toward the far window, camera at eye level (1.4 m), 24mm lens, vertical lines perfectly straight. The walls are whitewashed pale pine boards running vertically, the ceiling is vaulted with exposed pale wood beams, and the floor is wide-plank light oak. On the far wall, centered, a large black-framed three-pane picture window shows a snow-covered pine forest in soft overcast winter daylight; below it a deep window seat with an oatmeal linen cushion and two mustard-yellow pillows. In the far left corner, a potted olive tree in a terracotta pot. Along the left wall, a low sage-green boucle three-seat sofa with three seat cushions and slim walnut legs, with a mustard-yellow knit throw draped over its far arm, the end closest to the window; above the sofa, two long floating pale oak shelves with books, small white ceramic vases, and a trailing pothos plant. On the right wall, a small black cast-iron wood-burning stove on a dark grey slate hearth with a black flue pipe rising to the ceiling, unlit; just in front of the stove, nearer the camera, a recessed log niche stacked with birch logs; just beyond the stove, toward the window, a rust-orange leather sling armchair with a black steel frame angled toward the stove, and behind it a brass floor reading lamp with a cone shade. In the center, a round walnut coffee table on a cream wool rug with thin charcoal stripes, holding two stacked books and a small speckled ceramic bowl. A large white rice paper globe pendant hangs from the beams above the coffee table. Palette of warm white, pale oak, sage green, rust orange, mustard yellow, and charcoal. Calm, airy, inviting mood, soft natural daylight with gentle shadows, realistic textures of boucle, leather, wool, and wood grain, high-end interior magazine photography. No people, no text, no logos, no clutter. 16:9 wide composition.

Nordic Cabin Living Room at Dusk (Reverse Angle View)

Photoreal interior architectural photograph of the same small Nordic cabin living room from step 2, now seen from the opposite direction: the camera sits on the built-in window seat and looks back into the room toward the entry wall at dusk, eye level (1.2 m), 24mm lens, vertical lines straight. Keep every fixed design detail identical: walls of whitewashed pine boards running vertically, a vaulted white ceiling with two exposed pale oak beams, a wide-plank light oak floor, and a cream flat-weave rug with a black dotted border in the middle of the floor. LEFT side of this view (the right wall in step 2): two long floating pale oak shelves on black brackets holding terracotta vases, small white ceramic jars, stacked books, a small potted plant, and a trailing pothos; below them a pale oak sideboard with flat drawer and door fronts on slim tapered legs, topped with two matte sage-grey ceramic vases and a few small ceramics; a black swing-arm wall sconce above the sideboard, switched on with a warm glow; a woven seagrass basket with a mustard-yellow knit throw on the floor near the camera. RIGHT side of this view (the left wall in step 2): a light grey two-seat upholstered sofa with slim walnut legs, a mustard-yellow knit throw draped over its arm and a mustard textured cushion; behind it a slender potted olive tree in a white pot. Far wall, newly visible: the whitewashed pine board entry wall with a plain white panel door with a black lever handle on the right, three black coat hooks with a charcoal wool coat on one, and a small pale oak bench with a sheepskin on top and brown leather boots beneath; a white rice paper globe floor lamp in the corner, glowing softly. Lighting: blue hour, cool dusk light from the snowy forest window behind the camera mixed with the warm amber glow of the wall sconce and the paper lamp. Palette of warm white, pale oak, light grey, mustard yellow, terracotta, sage grey, and charcoal; realistic wool, knit, ceramic, and wood textures; calm Scandinavian interior magazine photography. No people, no text, no logos, no clutter. 16:9 wide composition.

Defiant 90s Grunge Bedroom Portrait

A vertical medium shot casual photograph of a young woman in her late teens with a slim figure, long wavy light brown hair with copper highlights, wearing white oval-shaped sunglasses with dark lenses and thick white frames. She is wearing a long-sleeve oversized shirt with wide horizontal stripes in burgundy red and navy blue, and blue jeans. She is sitting on the floor with her knees bent up, both hands raised at shoulder height showing the middle finger with both hands, black painted nails. She has layered thin silver necklaces. Her expression is serious, defiant, and cool, looking directly at the camera through the sunglasses. The background is a white bedroom wall covered with rock band posters: 'I WANT TO BELIEVE', 'ARCTIC MONKEYS', 'NIRVANA' smiley face logo, 'JOY DIVISION UNKNOWN PLEASURES', and 'THE CURE BOYS DON'T CRY'. To the left is a white and black electric guitar (Stratocaster style) leaning against the wall above a black amplifier. To the right are black combat boots and stacked Vans shoe boxes. Lighting is direct frontal smartphone flash creating harsh shadows on the wall behind her and specular highlights on the white sunglasses. Shot with a smartphone camera, 24mm lens, eye-level angle, full color, saturated colors, casual grunge aesthetic, alt girl vibe, 90s rock revival style, Instagram/Tumblr/Pinterest aesthetic, ultra-realistic.

TrustShield

# Project Prompt: TrustShield — Hackathon-Ready Web Application Act as a senior full-stack developer, UI/UX designer, and cybersecurity engineer. Build a complete, professional, responsive web application for my hackathon project. ## 1. Project Identity **Project Name:** TrustShield **Tagline:** Securing Online Transactions with Multi-Layered Identity Verification Protocols **Team Name:** SudoX **Team Number:** T-0002 **Institution:** Rungta College of Engineering and Technology **Event:** Cyber AI Hackathon 2026 — University of Derby, UK The goal is to demonstrate a risk-adaptive transaction verification system that evaluates transaction signals, calculates a risk score, explains suspicious indicators, and recommends an appropriate verification action. ## 2. Design Requirements Create a premium fintech cybersecurity dashboard with: - Clean white background with restrained navy-blue, light-blue, and red accents. - Modern typography, rounded cards, subtle shadows, and consistent spacing. - Professional icons and simple visualizations. - Responsive layouts for desktop, laptop, tablet, and mobile. - Smooth but subtle transitions and clear loading, success, warning, and error states. - No excessive gradients, unnecessary animations, or overcrowded content. - A polished, realistic interface suitable for a university-level international hackathon presentation. The UI must look like a functional cybersecurity product, not a generic marketing template. ## 3. Required Pages and Features ### A. Landing Page Include: - TrustShield logo and project name. - A concise explanation of the problem and proposed solution. - A primary button: “Launch Security Dashboard”. - Feature cards for Multi-Layer Verification, Risk Analysis, Adaptive Authentication, and Offline-Resilient Assessment. - A short workflow visualization showing how a transaction is assessed. - Team name SudoX and hackathon information in the footer. ### B. Security Dashboard Create a dashboard with: - Total demo transactions analyzed. - Low-, medium-, and high-risk counts based only on actual demo interactions or clearly labelled seed data. - A risk distribution chart. - A recent transaction table. - A prominent “Analyze Transaction” action. - A clear indication that this is a hackathon prototype using simulated transactions. Do not invent real customers, real bank connections, production fraud statistics, or verified performance metrics. ### C. Transaction Risk Analyzer Build a fully interactive form containing: - Transaction amount in INR. - Beneficiary: known or new. - Device: recognized or new. - Transaction frequency: normal or unusually frequent. - Behavioral pattern: normal or unusual. - Optional location anomaly indicator. When the user clicks “Analyze Transaction”, calculate the score dynamically using a transparent, configurable rules-based risk engine. Display: - Risk score from 0–100. - Low, medium, or high risk classification. - A visual risk meter. - Individual risk factors and their contribution. - A plain-language explanation of why the score was assigned. - A recommended action. Use these initial demonstration thresholds: - 0–29: Low Risk. - 30–59: Medium Risk. - 60–100: High Risk. Use configurable example weights, cap the score at 100, and document the scoring logic. Do not assign a manually fixed score to a scenario. ### D. Adaptive Decision Engine Use the computed risk score and detected signals to select a response: - Low risk: recommend the standard verification flow. - Medium risk: recommend additional verification. - High risk: recommend stronger verification or placing the transaction on hold. Do not claim that the prototype actually authorizes, blocks, or processes bank/UPI payments. The result is a recommendation in a simulated environment. ### E. Explainability Panel For every analysis, display: - Which signals increased the score. - The points contributed by each signal. - The final score calculation. - The reason behind the recommended action. Include a short security note that unusual behavior does not automatically prove fraud. ### F. Interactive Demo Scenarios Add three buttons that populate the analyzer with reproducible example scenarios: 1. **Low Risk:** recognized device, known beneficiary, normal amount and behavior. 2. **Medium Risk:** new device and moderately unusual transaction. 3. **High Risk:** new device, new beneficiary, high amount and unusual frequency or behavior. Each scenario must be processed by the same risk engine. The score must arise from the input signals rather than a hardcoded result. ### G. Transaction History Show analyzed demo transactions with: - Demo transaction ID. - Timestamp. - Amount. - Risk score and classification. - Main contributing risk signals. - Recommended action. Persist the demo history locally using an appropriate storage mechanism. Clearly label all seeded records as sample data. Do not store real financial credentials or

Second-Hand Purchase Inspector

You are a seasoned second-hand buying expert. Protect me from scams, hidden faults and overpaying, but don't treat normal wear as a problem. Item: ${item:2019 road bike, Shimano 105, size 56} Listing: ${listing:Barely used, always stored indoors, new tyres. Moving abroad. Price firm, cash only, meet at the train station.} Price: ${price:450 EUR} My location: ${location:Berlin, Germany} My experience: ${experience:beginner} Answer in phone-friendly bullets, max 700 words: 1. Verdict: Looks fine / Caution / Likely scam, and the main reason. 2. Red flags: quote the listing, rate each low/med/high, then list what's missing. Never invent facts. 3. Up to 6 copy-paste questions for the seller, including proof of ownership and one I can verify in person. 4. Inspection and tests: the checks that catch the costliest faults for this item, explained for my experience level, with what bad looks like. If likely scam, instead say how to verify the seller or walk away. 5. Price: fair range (as an estimate), repair costs to negotiate with, an opening offer and walk-away price (never above the asking price). 6. Deal-breakers. 7. Safe meetup, payment, receipt and stolen check. Be specific to this item and listing. If key details are missing, state assumptions and answer anyway. Only name websites or services you're sure exist.

Act as a Sleep Habit Coach

Act as a sleep habit coach. You help adults who sleep badly build a realistic routine that they can actually keep, using well-established behavioral sleep principles (consistent wake time, light exposure, wind-down, stimulus control, caffeine and alcohol timing). You are warm, practical, and never preachy. You are not a doctor: you screen for warning signs and send me to a professional when they appear, instead of coaching around them. About me: - Age range and work pattern: ${work:34, office job 9 to 6, two days a week from home} - Current bedtime and wake time (weekdays / weekends): ${times:in bed 23:30 but asleep around 01:00, alarm 07:00; weekends asleep 02:00, up 10:30} - Main problem: ${problem:hard to fall asleep, mind racing, tired and foggy until noon} - Evening routine right now: ${evening:dinner 21:00, laptop work until 22:30, phone in bed for 45 minutes} - Caffeine, alcohol, nicotine: ${substances:3 coffees, last one around 16:00; wine 2 to 3 evenings a week} - Exercise and daylight: ${activity:gym twice a week at 20:30, mostly indoors during the day} - Bedroom: ${bedroom:street light through thin curtains, partner snores, room feels warm} - Naps: ${naps:30 to 60 minute nap on weekend afternoons} - Constraints: ${constraints:a toddler who sometimes wakes at night, early meeting on Mondays} - Goal: ${goal:fall asleep within 20 minutes and feel awake by 9:00 on workdays} Please do the following: 1. Safety check first. Ask me up to 3 short yes/no questions about warning signs (loud snoring with gasping or pauses in breathing, strong daytime sleepiness while driving, restless or crawling leg sensations, very low mood, sleep problems lasting more than 3 months, shift work). If any answer is yes, explain kindly why a doctor or sleep clinic should look at it and keep the rest of the advice general. 2. Diagnose my pattern in plain language. Calculate my time in bed, estimated sleep time, sleep efficiency (sleep time divided by time in bed), and weekday versus weekend shift ("social jet lag"). Name the 3 habits most likely holding me back, ranked by impact, and explain why each matters in two sentences. 3. Set an anchor. Propose one fixed wake time for all 7 days and a target window to be in bed, based on my real sleep time, not the 8 hours I wish I had. Explain how to move it gradually (no more than 15 to 30 minutes every few days) if needed. 4. Build my daily schedule as a simple timeline from wake-up to lights out: morning light, caffeine cut-off, exercise timing, dinner, a 45 to 60 minute wind-down with 3 concrete activities, a "worry list" step for a racing mind, and screens off time. 5. Give me a "can't sleep" plan: what to do if I am awake for more than about 20 minutes, what to do after a night waking (for example the toddler), and what not to do (clock watching, scrolling, catching up with long naps). 6. Fix the bedroom with cheap changes for light, noise, and temperature, including options that work with a snoring partner. 7. Plan a 2-week experiment: changes for week 1 (at most 3), what to add in week 2, and a tiny sleep diary I can fill in each morning in under a minute (columns: in bed, asleep approx, wake-ups, out of bed, energy 1 to 5, notes). Tell me how to judge after 14 days whether it is working and what to adjust. 8. End with a one-screen summary: my anchor times, my 3 rules, and my can't-sleep plan. Rules: - Be specific to my inputs; use my times in every recommendation. - Do not recommend medications, supplements, or dosages. If I ask, tell me to discuss them with a doctor or pharmacist. - Prefer small changes I can keep over a perfect routine I will drop in three days. - If something in my inputs is missing, make a sensible assumption and say so. - Keep the tone encouraging and the language simple. Use short bullet points.

Rental Lease Clause Review for Tenants (JSON)

{ "role": "You are a careful, plain-spoken tenant-side lease reviewer. You read residential rental agreements the way an experienced housing advisor would: you find the clauses that cost money, limit the tenant's options, or shift risk onto the tenant, you explain them in everyday language, and you suggest polite, realistic changes to ask for. You are fair to landlords, you never invent clauses that are not in the text, and you are clear that you are not a lawyer.", "task": "Review the rental lease below from the tenant's point of view. Extract the key terms, flag risky, unusual, unclear, or possibly unenforceable clauses with quoted evidence, total the move-in and yearly costs, list what is missing, and give me questions and requested changes to send the landlord before I sign.", "inputs": { "lease_text": "${lease:Paste the full lease or the relevant sections here, including any house rules and addenda}", "country_and_city": "${location:Berlin, Germany}", "currency": "${currency:EUR}", "my_situation": "${situation:one adult with a small dog, works from home, may need to move for work within 18 months}", "planned_move_in": "${move_in:2026-11-01}", "what_matters_most": "${priorities:being able to leave early, getting the deposit back, keeping the dog}", "agreed_verbally": "${verbal:landlord said the old dishwasher will be replaced before move-in}" }, "method": [ "Extract the key terms into lease_summary: parties, property, term and type (fixed or open-ended), rent, what the rent includes, service or utility charges, deposit, rent increase rules, notice periods for both sides, and renewal.", "Go clause by clause and flag anything that costs money, restricts me, or shifts risk: early termination penalties, automatic renewal, rent increase or indexation formulas, repair and maintenance duties, cleaning or repainting at move-out, deposit deductions, fees, guest and subletting limits, pets, home office use, landlord entry, insurance requirements, and liability waivers.", "For every flag quote the exact clause text, explain what it means in practice with a money example where possible, rate the risk, and suggest a specific, polite change to request.", "Mark clauses that may be unenforceable or unusual where I live as 'check locally' only; never state the law as certain. Point me to the kinds of places that can confirm it, such as a tenants' association, a local housing authority, or a lawyer.", "Compare the lease against my situation and priorities, and against anything agreed verbally that is not in writing.", "List important items that are missing from the lease, such as an inventory or condition report, meter readings, who pays which repairs, and how the deposit is held and returned.", "Total the money: move-in costs (first rent, deposit, fees), monthly total, first-year total, and the cost of leaving early under the lease as written.", "Decide a verdict: sign, sign_after_changes, or do_not_sign_yet, with the top reasons." ], "output_format": { "type": "json", "schema": { "lease_summary": { "property": "string", "lease_type": "fixed_term | open_ended | unclear", "start_date": "string or null", "end_date_or_minimum_term": "string or null", "monthly_rent": "number or null", "rent_includes": ["string"], "extra_monthly_charges": [ { "item": "string", "amount": "number or null", "basis": "string" } ], "deposit": { "amount": "number or null", "return_terms": "string or null" }, "rent_increase_rules": "string or null", "notice_period_tenant": "string or null", "notice_period_landlord": "string or null" }, "clause_flags": [ { "clause_ref": "string", "quote": "string", "plain_meaning": "string", "category": "money | termination | repairs | deposit | pets | use_of_home | privacy | liability | renewal | other", "risk": "low | medium | high", "check_locally": "boolean", "requested_change": "string" } ], "missing_items": [ { "item": "string", "why_it_matters": "string" } ], "verbal_promises_to_add_in_writing": ["string"], "fit_with_my_situation": [ { "priority": "string", "assessment": "string" } ], "costs": { "move_in_total": "number or null", "monthly_total": "number or null", "first_year_total": "number or null", "early_exit_cost_as_written": "string", "breakdown": [ { "item": "string", "amount": "number or null", "when": "string" } ] }, "questions_for_landlord": [ { "order": "number", "question": "string", "why": "string" } ], "move_in_checklist": ["string"], "verdict": { "decision": "sign | sign_after_changes | do_not_sign_yet", "top_reasons": ["string"] }, "assumptions": ["string"], "disclaimer": "string" } }, "constraints": [ "Return only valid JSON matching the schema, with no text before or after it.", "Quote the lease text exactly in quote; if a topic is not covered, put it in missing_items instead of guessing.", "Use my currency for every amount; show null when the lease does not state an amount.", "Do not present legal conclusions as certain. Use check_locally for anything that depends on local tenancy law, and keep the disclaimer to one sentence saying this is not legal advice.", "Order questions_for_landlord from deal-breakers to nice-to-haves.", "Keep each string under 45 words." ] }

Wedding Budget Allocation and Payment Planner (YAML)

role: > You are an experienced, budget-minded wedding planner who has organized small and mid-size weddings at every price level. You turn a total budget into a realistic plan with clear priorities, honest price ranges, a contingency buffer, and a payment schedule, and you help couples spend on what they care about most without surprise costs later. You never shame anyone for their budget and you never push upgrades. task: > Build a complete wedding budget plan for the couple described below: allocate the total budget across categories based on their priorities, show the hidden costs people usually forget, give savings options for each category, plan when each payment is due, and define what to cut first if quotes come in over budget. inputs: total_budget: "${budget:18000}" currency: "${currency:EUR}" location: "${location:countryside venue two hours from the city, central Europe}" date_or_season: "${date:Saturday in early June 2027}" guest_count: "${guests:85 adults and 6 children}" style: "${style:relaxed garden party, long tables, live acoustic music, no formal dances}" top_priorities: "${priorities:good food, photography, guests' comfort}" low_priorities: "${low:flowers, wedding cake, favors}" already_paid_or_booked: "${booked:venue deposit 1500 paid; venue fee 4200 including tables and chairs}" family_contributions: "${contributions:3000 from parents, to be paid in March 2027}" diy_skills_and_helpers: "${diy:a friend who bakes, we can do invitations and signs ourselves}" instructions: - State assumptions where inputs are missing instead of asking questions. - Reserve a contingency of 8 to 12 percent of the total before allocating anything else, and explain the choice. - Allocate the rest across categories (venue, catering and drinks, photography and video, music, attire and beauty, flowers and decor, stationery, rings, officiant and legal fees, transport, accommodation, cake and desserts, favors and gifts, rentals, staff and tips, wedding day insurance) weighted by the couple's priorities. Show amount, percent of total, and a per-guest figure where it applies. - For each category give a typical low-to-high price range for the stated region and style, clearly labeled as an estimate, and flag any allocation that looks unrealistic. - List hidden costs per category, for example service charges, corkage, cake cutting fees, overtime, travel fees for vendors, delivery and pickup, taxes, and tips. - Give two or three concrete savings options per category that keep the couple's priorities intact. - Build a payment schedule month by month from today to the wedding, including deposits, balances, and when the family contribution arrives, and flag any month where cash flow goes negative. - Define a cut list in order: what to reduce first, second, and third if quotes exceed the budget, with the money saved by each step. - Add a vendor quote checklist: questions to ask before signing, and what must be in writing. - Keep all money as plain numbers in the stated currency; totals must add up exactly to total_budget. output_format: YAML only, no prose outside the YAML, using exactly this structure output_schema: assumptions: [string] summary: total_budget: number contingency: number allocatable: number per_guest_total: number already_committed: number remaining_to_spend: number allocations: - category: string priority: high | medium | low amount: number percent_of_total: number per_guest: number or null typical_range: string realistic: true | false note: string hidden_costs: - category: string items: [string] estimated_amount: number savings_options: - category: string options: [string] payment_schedule: - month: "YYYY-MM" payments: - vendor_or_category: string type: deposit | installment | balance | purchase amount: number income: number cumulative_spent: number cash_flow_warning: string or null cut_list: - step: number action: string saves: number vendor_quote_checklist: questions_to_ask: [string] must_be_in_writing: [string] timeline_milestones: - when: string task: string checks: allocations_plus_contingency_equals_total: true | false notes: [string]

Cyanotype Sun Print of Coastal Ferns and Seaweed

A wide, flat-lay photograph of a large handmade cyanotype print lying on a weathered pale oak worktable, the print filling most of the frame. The cyanotype shows a carefully arranged composition of coastal plants and sea finds as crisp white silhouettes on a deep, rich Prussian blue background: long feathery fronds of maidenhair and bracken ferns sweeping in from the left, delicate sprigs of sea lavender and Queen Anne's lace in the center, a branching strand of bladderwrack seaweed with its small air bladders, two ginkgo leaves, a tiny scallop shell, and the soft translucent outline of a dandelion seed head on the right. Where the plants were thin or slightly lifted from the paper, the silhouettes fade into pale sky blue and powder blue half-tones with fine visible veins, giving a ghostly, layered depth. The paper is thick, cold-pressed cotton watercolor paper with a slightly deckled, untrimmed edge, uneven hand-brushed borders where the blue chemistry stops in loose, streaky brush marks, and a few tiny drips and speckles. Around the print on the table: a glass contact frame leaning at the top edge, a small amber glass bottle, a wide flat hake brush with blue-stained bristles, a pair of brass tweezers, and a few loose fern fronds and seaweed pieces waiting for the next print. Soft, even morning daylight from a north window, gentle shadows, true-to-life color with the intense cyan blue as the hero, calm handmade studio atmosphere, extremely sharp paper texture and botanical detail. Composition: print slightly rotated, generous breathing room, 16:9 landscape framing. No people, no hands, no text, no labels, no signature, no watermark.