LPD-Direct: Logical Process Design Language | unfck.tech
LPD-Direct
Simple Process Language Specification
1. Introduction and Philosophy
LPD-Direct (Logical Data Flow) is a declarative pseudocode language for designing, documenting, and automating business and technical processes.
Its main goal is to eliminate the communication barrier between business experts (who know why we do something) and technical teams (who know how to do it). The syntax forces you to connect technical instructions with their business justification.
LPD-Direct Fundamentals:
- Readability: Code must be understandable by non-technical people.
- Context: Every action must have an explicitly defined business purpose.
- Full Control: The language handles not just success ("happy path"), but also errors, human decisions, and artificial intelligence.
- Unambiguous: Each construct has exactly one interpretation.
2. Script Structure
Every process described in LPD-Direct consists of three main sections:
- Trigger (TRIGGER): Definition of what starts the process.
- Process Body: Logical sequence of operations divided into phases (e.g., Collection, Processing, Decisions).
- Completion: Explicit signal of flow end.
2.1. The Iron Rule: Double Comment
Every operational command must be preceded by two comments. This is not optional.
// What we're doing:(Technical description of the action)// Why:(Business justification)
Exceptions: TRIGGER and SYSTEMS don't require double comments (they have built-in descriptions).
// What we're doing: Filter orders with status 'Cancelled'.
// Why: To avoid calculating commission on sales that didn't complete.
FILTER ORDERS WHERE Status != 'Cancelled' AS COMPLETED_ORDERS 2.2. System Declaration (SYSTEMS)
Optional section defining external systems and software used in the process. Placed directly after TRIGGER, before the first SET/LOAD.
Syntax:
// SYSTEMS:
// - <System Name>: <Type> - <Description of what it contains/does>
// - <System Name>: <Type> - <Description> Example:
// TRIGGER: SCHEDULE EVERY DAY AT 09:00 CET
// SYSTEMS:
// - Company ERP: REST API - Invoicing and client payment management system
// - HR Database: PostgreSQL - Employee and organizational structure database
// - Salesforce: REST API - CRM for lead and contact management
// - Mail Service: SMTP - Mail server for automated notifications
// - Slack: Webhook - Team communicator for operational alerts
// What we're doing: Set today's date.
// Why: For deadline calculations.
SET TODAY = CURRENT_DATE() Purpose: Documents process dependencies on external systems - facilitates onboarding new people and identifying failure points.
Entry format:
- System Name: Name used in LOAD/SEND aliases
- Type: REST API, GraphQL, SQL (PostgreSQL/MySQL), SMTP, Webhook, File System, etc.
- Description: Brief description of system's role in the process (1 sentence)
3. Data Types and Literals
3.1. Basic Types
| Type | Example | Description |
|---|---|---|
| STRING | 'Text' | Text in single quotes |
| NUMBER | 123, 45.67 | Integer and decimal numbers |
| BOOLEAN | TRUE, FALSE | Logical values |
| NULL | NULL | No value |
| DATE | 2024-01-15 | Date in ISO 8601 format |
| DATETIME | 2024-01-15T09:00:00Z | Date and time in ISO 8601 format |
3.2. Complex Types
| Type | Example | Description |
|---|---|---|
| DATASET | CUSTOMERS | Table (collection of records) |
| RECORD | Customer_ID, Name | Single row in dataset |
| LIST | ['A', 'B', 'C'] | Simple list of values |
4. Variables and Naming Conventions
4.1. Variables (SET)
Syntax:
SET VARIABLE_NAME = value Rules:
- Variable names in
UPPER_SNAKE_CASE - Each SET must have double comment
- Variables are immutable - use OVERRIDE to change value
Example:
// What we're doing: Set the analysis start date.
// Why: To analyze last quarter's data.
SET START_DATE = '2024-01-01'
// What we're doing: Set calculation threshold.
// Why: We only want to process orders over $100.
SET MIN_AMOUNT = 100 4.2. Datasets (LOAD, FILTER, etc.)
Syntax:
LOAD <source> AS DATASET_NAME Rules:
- Dataset names in
UPPER_SNAKE_CASE - Column names in
PascalCaseor in quotes if spaces
Example:
// What we're doing: Load customer data from database.
// Why: To analyze purchasing behavior.
LOAD SQL FROM 'CRM_DB' QUERY 'SELECT * FROM customers' AS CUSTOMERS 5. Basic Operations
5.1. LOAD - Data Loading
Loads data from external sources.
LOAD from SQL:
// What we're doing: Load sales data.
// Why: To calculate monthly revenue.
LOAD SQL FROM 'Database' QUERY 'SELECT * FROM sales WHERE month = 1' AS SALES
ON ERROR: RETRY 3 TIMES THEN STOP LOAD from API:
// What we're doing: Fetch customer list from CRM.
// Why: To send marketing emails.
LOAD API FROM 'https://crm.company.com/api/customers' AS CUSTOMERS
ON ERROR: SKIP AND LOG 'CRM unavailable' LOAD from FILE:
// What we're doing: Load price list from CSV.
// Why: To update product prices.
LOAD FILE FROM '/data/prices.csv' FORMAT CSV AS PRICES
ON ERROR: STOP AND ALERT 'Data Team' 5.2. FILTER - Data Filtering
Filters dataset based on condition.
Syntax:
FILTER DATASET WHERE condition AS NEW_DATASET Example:
// What we're doing: Filter active customers only.
// Why: To avoid sending offers to inactive accounts.
FILTER CUSTOMERS WHERE Status = 'Active' AS ACTIVE_CUSTOMERS 5.3. CALCULATE - Calculations
Performs calculations on dataset.
Syntax:
CALCULATE on DATASET:
New_Column = expression
Another_Column = expression
AS NEW_DATASET Example:
// What we're doing: Calculate profit margin per transaction.
// Why: To identify most and least profitable products.
CALCULATE on SALES:
Profit_Amount = Sale_Price - Cost_Price
Profit_Margin = (Profit_Amount / Sale_Price) * 100
AS SALES_WITH_MARGIN 5.4. GROUP - Grouping and Aggregation
Groups data and calculates aggregates.
Syntax:
GROUP DATASET BY column_list:
Aggregate_Column = AGGREGATE_FUNCTION(column)
AS NEW_DATASET Aggregate functions: SUM, AVG, COUNT, MIN, MAX
Example:
// What we're doing: Calculate total sales per salesperson.
// Why: For commission calculation.
GROUP SALES BY Salesperson_ID:
Total_Sales = SUM(Amount)
Order_Count = COUNT(Order_ID)
AS SALES_BY_PERSON 5.5. SORT - Sorting
Sorts dataset.
Syntax:
SORT DATASET BY column1 ASC, column2 DESC AS NEW_DATASET Example:
// What we're doing: Sort customers by total spending.
// Why: To identify VIP customers first.
SORT CUSTOMERS BY Total_Spent DESC AS VIP_CUSTOMERS 5.6. JOIN - Joining Datasets
Joins two datasets.
Syntax:
JOIN DATASET1 WITH DATASET2
ON DATASET1.column = DATASET2.column
TYPE INNER/LEFT/RIGHT/FULL
AS NEW_DATASET Example:
// What we're doing: Match orders with customer data.
// Why: To add customer info to each order.
JOIN ORDERS WITH CUSTOMERS
ON ORDERS.Customer_ID = CUSTOMERS.Customer_ID
TYPE LEFT
AS ORDERS_WITH_CUSTOMERS 6. Control Flow
6.1. IF/ELSE - Conditional Execution
Syntax:
IF condition THEN
// operations
ELSE
// alternative operations
END IF Logical operators: AND, OR, NOT
Comparison operators: =, !=, <, >, <=, >=
Example:
// What we're doing: Check if sales threshold is met.
// Why: To decide if bonus should be paid.
IF TOTAL_SALES > 100000 AND Month = 'December' THEN
// What we're doing: Calculate bonus.
// Why: Year-end bonus for achieving target.
SET BONUS = TOTAL_SALES * 0.05
ELSE
// What we're doing: Set bonus to zero.
// Why: Target not met.
SET BONUS = 0
END IF 6.2. FOR EACH - Iteration
Syntax:
FOR EACH row IN DATASET DO
// operations on each row
END FOR Example:
// What we're doing: Process each customer individually.
// Why: Each customer needs personalized calculation.
FOR EACH customer IN VIP_CUSTOMERS DO
// What we're doing: Calculate individual discount.
// Why: VIP customers get tiered discounts.
IF customer.Total_Spent > 50000 THEN
SET customer.Discount = 15
ELSE
SET customer.Discount = 10
END IF
END FOR 7. Error Handling (ON ERROR)
Every risky operation (LOAD, SEND, ASK_AI) must have ON ERROR handling.
7.1. Error Strategies
STOP: Terminates process immediately
ON ERROR: STOP STOP AND ALERT: Terminates and sends alert
ON ERROR: STOP AND ALERT 'Admin Team' RETRY: Attempts operation again
ON ERROR: RETRY 3 TIMES THEN STOP SKIP: Skips failed operation and continues
ON ERROR: SKIP AND LOG 'Optional data unavailable' Example:
// What we're doing: Load pricing data from external API.
// Why: To update product catalog.
LOAD API FROM 'https://vendor.com/api/prices' AS VENDOR_PRICES
ON ERROR: RETRY 3 TIMES THEN SKIP AND LOG 'Vendor API unavailable' 8. Human and AI Integration
8.1. AWAIT APPROVAL - Human Decisions
Pauses process for human approval.
Syntax:
AWAIT APPROVAL FROM 'role' ON DATASET
SHOW: 'column1', 'column2'
QUESTION: 'Question text?'
TIMEOUT: duration
AS NEW_DATASET Example:
// What we're doing: Request approval for large refunds.
// Why: Amounts over $10K need management approval.
AWAIT APPROVAL FROM 'Finance Manager' ON LARGE_REFUNDS
SHOW: 'Customer_Name', 'Amount', 'Reason'
QUESTION: 'Approve these refunds?'
TIMEOUT: 24 HOURS
AS APPROVED_REFUNDS 8.2. ASK_AI - AI Agent Tasks
Delegates task to AI agent.
Syntax:
ASK_AI on DATASET:
TASK: 'Task description with [Column] references'
RETURN: New_Column_Name
AS NEW_DATASET Example:
// What we're doing: Generate personalized email copy.
// Why: AI writes better personalized messages than templates.
ASK_AI on CUSTOMERS:
TASK: 'Write friendly email to [First_Name] mentioning their recent purchase of [Product]. Max 100 words.'
RETURN: Email_Body
AS CUSTOMERS_WITH_EMAILS 9. Output Operations
9.1. SEND - Sending Data
SEND to API:
// What we're doing: Send processed orders to fulfillment system.
// Why: To trigger warehouse shipping.
SEND READY_ORDERS TO API 'https://warehouse.com/api/orders'
ON ERROR: RETRY 5 TIMES THEN ALERT 'Operations' SEND to FILE:
// What we're doing: Export report to Excel file.
// Why: For manual review by finance team.
SEND MONTHLY_REPORT TO FILE '/reports/january_2024.xlsx' FORMAT XLSX
ON ERROR: STOP AND ALERT 'IT Support' SEND EMAIL:
// What we're doing: Email report to management.
// Why: Daily summary for executives.
SEND EMAIL TO 'ceo@company.com'
SUBJECT 'Daily Sales Report'
BODY 'Total: [TOTAL_SALES]'
ON ERROR: SKIP AND LOG 'Email failed' SEND ALERT:
// What we're doing: Send Slack alert.
// Why: Notify team of critical issue.
SEND ALERT 'Inventory below minimum!' TO 'Slack / #operations' 10. Complete Examples
10.1. Collections Process with AI and Approvals
// TRIGGER: SCHEDULE EVERY DAY AT 09:00 CET
// What we're doing: Set current date.
// Why: For calculating payment deadlines.
SET TODAY = CURRENT_DATE()
// --- Phase 1: Data Collection ---
// What we're doing: Load all unpaid invoices from ERP.
// Why: To identify customers with outstanding payments.
LOAD API FROM 'https://erp.company.com/api/invoices?status=unpaid' AS ALL_OVERDUE
ON ERROR: STOP AND ALERT 'ERP Admin'
// What we're doing: Filter invoices overdue by more than 7 days.
// Why: Give customers 7-day grace period before collections.
FILTER ALL_OVERDUE WHERE Payment_Due <= SUBTRACT_DAYS(TODAY, 7) AS OVERDUE_TO_COLLECT
// --- Phase 2: AI and Decisions ---
// What we're doing: Ask AI to generate personalized, polite email for each customer.
// Why: So communication is customer-specific, not robotic.
ASK_AI on OVERDUE_TO_COLLECT:
TASK: 'Write brief reminder about invoice [Invoice_No] amount [Amount]. Use polite tone.'
RETURN: Email_Body
AS PREPARED_EMAILS
// What we're doing: Split process based on amount.
// Why: Large amounts are relationally risky, want human review before sending.
IF PREPARED_EMAILS.Amount > 10000 EUR THEN
// --- VIP Path (requires approval) ---
// What we're doing: Pause process for these records and send request to Finance Manager.
// Why: Avoid mistakes with key customers.
AWAIT APPROVAL FROM 'Finance Manager' ON PREPARED_EMAILS
SHOW: 'Customer', 'Amount', 'Email_Body'
QUESTION: 'Send this VIP reminder?'
AS APPROVED_VIP
// What we're doing: Send only approved VIP emails.
// Why: To reach key customers with confirmed communication.
SEND APPROVED_VIP TO API 'https://mail.company.com/send'
ELSE
// --- Standard Path (automatic) ---
// What we're doing: Send emails automatically for smaller amounts.
// Why: Save manager time on routine reminders.
SEND PREPARED_EMAILS TO API 'https://mail.company.com/send'
END IF 10.2. Sales Reporting with Margin Analysis
// TRIGGER: SCHEDULE EVERY 1st DAY OF MONTH AT 00:00 UTC
// What we're doing: Set time variables for previous month.
// Why: So report covers complete month.
SET START_DATE = SUBTRACT_DAYS(CURRENT_DATE(), 30)
SET END_DATE = CURRENT_DATE()
// What we're doing: Load sales data from production database.
// Why: To analyze last month's sales performance.
LOAD SQL FROM 'ProductionDB' QUERY 'SELECT * FROM sales WHERE sale_date BETWEEN @START_DATE AND @END_DATE' AS SALES
ON ERROR: RETRY 3 TIMES THEN STOP AND ALERT 'DBA Team'
// What we're doing: Calculate margin for each transaction.
// Why: To identify most and least profitable products.
CALCULATE on SALES:
Margin_Amount = Sale_Price - Cost_Price
Margin_Percent = (Margin_Amount / Sale_Price) * 100
AS SALES_WITH_MARGIN
// What we're doing: Filter transactions with negative margin.
// Why: To identify products sold at a loss.
FILTER SALES_WITH_MARGIN WHERE Margin_Amount < 0 AS LOSS_PRODUCTS
// What we're doing: Check if there are loss products.
// Why: To decide if we need to alert management.
IF LOSS_PRODUCTS IS NOT EMPTY THEN
// What we're doing: Send alert about loss products.
// Why: So management can quickly respond to the issue.
SEND ALERT 'Warning: Products sold at a loss detected!' TO 'Slack / #management-alerts'
// What we're doing: Export details to file.
// Why: So management has full data for analysis.
SEND LOSS_PRODUCTS TO FILE '/reports/loss_products_month.xlsx' FORMAT XLSX
END IF
// What we're doing: Generate overall summary.
// Why: To get key sales metrics for the month.
CALCULATE on SALES_WITH_MARGIN:
Total_Sales = SUM(Sale_Price)
Total_Margin = SUM(Margin_Amount)
Average_Margin_Percent = AVG(Margin_Percent)
AS MONTHLY_REPORT
// What we're doing: Email monthly report.
// Why: So sales director receives automatic report.
SEND EMAIL TO 'sales.director@company.com' SUBJECT 'Monthly Sales Report' BODY 'Total sales: [Total_Sales], Margin: [Total_Margin]' 11. Author Checklist
Before deploying a process, verify:
- Every operational command has
// What we're doing:and// Why: - All variables and datasets use
UPPER_SNAKE_CASE - Columns are in PascalCase or in quotes (if they contain spaces)
- String literals are in single quotes
'...' - All risky operations (LOAD, SEND, ASK_AI) have
ON ERROR - Conditions IF use
AND/OR/NOT(not&&/||/!) - CALCULATE, GROUP, and ASK_AI blocks have 4-space indentation
- Every JOIN has specified type (INNER/LEFT/RIGHT/FULL)
- Every SORT has specified direction (ASC/DESC) for each column
- AWAIT APPROVAL has TIMEOUT if process can't wait indefinitely
- Use SET for declaration, OVERRIDE to overwrite (don't use SET twice on same variable)
- Process has clear TRIGGER at the beginning
- If process uses external systems, consider adding SYSTEMS section
- If using SKIP in ON ERROR, handle NULL case
Full specification with all examples: LPD-Direct Language Documentation (GitHub Gist)