tusktsk 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md ADDED
@@ -0,0 +1,759 @@
1
+ # TuskLang Ruby SDK
2
+
3
+ The official TuskLang Configuration SDK for Ruby with full support for parsing, generating, and executing TSK files with FUJSEN (function serialization). Built for Rails applications, Jekyll static sites, and DevOps automation.
4
+
5
+ ## 🚀 Features
6
+
7
+ - **Parse TSK Files**: Read and parse TOML-like TSK format
8
+ - **Generate TSK**: Create TSK files programmatically
9
+ - **FUJSEN Support**: Store and execute JavaScript functions within TSK files
10
+ - **@ Operator System**: Full FUJSEN intelligence operators
11
+ - **Rails Integration**: Application configuration and settings
12
+ - **Jekyll Support**: Static site generation
13
+ - **DevOps Automation**: Scriptable configuration with logic
14
+ - **Smart Contracts**: Perfect for blockchain and distributed applications
15
+ - **Complete CLI**: Universal command-line interface with all TuskLang commands
16
+
17
+ ## 📦 Installation
18
+
19
+ ### RubyGems
20
+ ```bash
21
+ # Add to your Gemfile
22
+ gem 'tusk_lang'
23
+
24
+ # Or install directly
25
+ gem install tusk_lang
26
+ ```
27
+
28
+ ### Rails Integration
29
+ ```ruby
30
+ # Gemfile
31
+ gem 'tusk_lang'
32
+
33
+ # config/application.rb
34
+ require 'tusk_lang'
35
+ ```
36
+
37
+ ### Jekyll Integration
38
+ ```ruby
39
+ # _plugins/tusk_lang.rb
40
+ require 'tusk_lang'
41
+
42
+ # _config.tsk
43
+ [site]
44
+ title = "My Jekyll Site"
45
+ description = "Built with TuskLang"
46
+ ```
47
+
48
+ ## 🎯 Quick Start
49
+
50
+ ### Basic Usage
51
+ ```ruby
52
+ require 'tusk_lang'
53
+
54
+ # Parse TSK file
55
+ tsk = TuskLang::TSK.from_string(<<~TSK)
56
+ [app]
57
+ name = "My Application"
58
+ version = "1.0.0"
59
+ debug = true
60
+
61
+ [config]
62
+ port = 8080
63
+ host = "localhost"
64
+ TSK
65
+
66
+ # Get values
67
+ app_name = tsk.get_value("app", "name")
68
+ port = tsk.get_value("config", "port")
69
+ puts "App: #{app_name}, Port: #{port}"
70
+ ```
71
+
72
+ ### FUJSEN Function Execution
73
+ ```ruby
74
+ # TSK with FUJSEN function
75
+ tsk = TuskLang::TSK.from_string(<<~TSK)
76
+ [calculator]
77
+ add_fujsen = """
78
+ function add(a, b) {
79
+ return a + b;
80
+ }
81
+ """
82
+
83
+ multiply_fujsen = """
84
+ function multiply(a, b) {
85
+ return a * b;
86
+ }
87
+ """
88
+ TSK
89
+
90
+ # Execute functions
91
+ sum = tsk.execute_fujsen("calculator", "add", 5, 3)
92
+ product = tsk.execute_fujsen("calculator", "multiply", 4, 7)
93
+ puts "Sum: #{sum}, Product: #{product}"
94
+ ```
95
+
96
+ ### @ Operator System
97
+ ```ruby
98
+ # TSK with @ operators
99
+ tsk = TuskLang::TSK.from_string(<<~TSK)
100
+ [api]
101
+ endpoint = "@request('https://api.example.com/data')"
102
+ cache_ttl = "@cache('5m', 'api_data')"
103
+ timestamp = "@date('%Y-%m-%d %H:%M:%S')"
104
+ user_count = "@Query('users').equalTo('status', 'active').count()"
105
+ TSK
106
+
107
+ # Execute operators
108
+ context = {
109
+ 'cache_value' => 'cached_data',
110
+ 'user_status' => 'active'
111
+ }
112
+
113
+ endpoint = tsk.execute_operators("@request('https://api.example.com/data')", context)
114
+ timestamp = tsk.execute_operators("@date('%Y-%m-%d %H:%M:%S')", context)
115
+ ```
116
+
117
+ ## 🖥️ Command Line Interface
118
+
119
+ The TuskLang Ruby SDK includes a complete CLI that implements the Universal CLI Command Specification.
120
+
121
+ ### Installation
122
+ ```bash
123
+ gem install tusk_lang
124
+ ```
125
+
126
+ ### Basic Usage
127
+ ```bash
128
+ # Show help
129
+ tsk --help
130
+
131
+ # Show version
132
+ tsk --version
133
+
134
+ # Get help for specific command
135
+ tsk help db
136
+ ```
137
+
138
+ ### Database Commands
139
+ ```bash
140
+ # Check database connection status
141
+ tsk db status
142
+
143
+ # Run migration file
144
+ tsk db migrate schema.sql
145
+
146
+ # Open interactive database console
147
+ tsk db console
148
+
149
+ # Backup database
150
+ tsk db backup [file]
151
+
152
+ # Restore from backup file
153
+ tsk db restore backup.sql
154
+
155
+ # Initialize SQLite database
156
+ tsk db init
157
+ ```
158
+
159
+ ### Development Commands
160
+ ```bash
161
+ # Start development server (default: 8080)
162
+ tsk serve [port]
163
+
164
+ # Compile .tsk file to optimized format
165
+ tsk compile config.tsk
166
+
167
+ # Optimize .tsk file for production
168
+ tsk optimize config.tsk
169
+ ```
170
+
171
+ ### Testing Commands
172
+ ```bash
173
+ # Run all test suites
174
+ tsk test all
175
+
176
+ # Run specific test suite
177
+ tsk test parser
178
+ tsk test fujsen
179
+ tsk test sdk
180
+ tsk test performance
181
+ ```
182
+
183
+ ### Service Commands
184
+ ```bash
185
+ # Start all TuskLang services
186
+ tsk services start
187
+
188
+ # Stop all TuskLang services
189
+ tsk services stop
190
+
191
+ # Restart all services
192
+ tsk services restart
193
+
194
+ # Show status of all services
195
+ tsk services status
196
+ ```
197
+
198
+ ### Cache Commands
199
+ ```bash
200
+ # Clear all caches
201
+ tsk cache clear
202
+
203
+ # Show cache status and statistics
204
+ tsk cache status
205
+
206
+ # Pre-warm caches
207
+ tsk cache warm
208
+
209
+ # Memcached operations
210
+ tsk cache memcached status
211
+ tsk cache memcached stats
212
+ tsk cache memcached flush
213
+ tsk cache memcached restart
214
+ tsk cache memcached test
215
+
216
+ # Show distributed cache status
217
+ tsk cache distributed
218
+ ```
219
+
220
+ ### Configuration Commands
221
+ ```bash
222
+ # Get configuration value by path
223
+ tsk config get server.port
224
+
225
+ # Check configuration hierarchy
226
+ tsk config check [path]
227
+
228
+ # Validate entire configuration chain
229
+ tsk config validate [path]
230
+
231
+ # Auto-compile all peanu.tsk files
232
+ tsk config compile [path]
233
+
234
+ # Generate configuration documentation
235
+ tsk config docs [path]
236
+
237
+ # Clear configuration cache
238
+ tsk config clear-cache [path]
239
+
240
+ # Show configuration performance statistics
241
+ tsk config stats
242
+ ```
243
+
244
+ ### Binary Performance Commands
245
+ ```bash
246
+ # Compile to binary format (.tskb)
247
+ tsk binary compile app.tsk
248
+
249
+ # Execute binary file directly
250
+ tsk binary execute app.tskb
251
+
252
+ # Compare binary vs text performance
253
+ tsk binary benchmark app.tsk
254
+
255
+ # Optimize binary for production
256
+ tsk binary optimize app.tsk
257
+ ```
258
+
259
+ ### Peanuts Commands
260
+ ```bash
261
+ # Compile .peanuts to binary .pnt
262
+ tsk peanuts compile config.peanuts
263
+
264
+ # Auto-compile all peanuts files in directory
265
+ tsk peanuts auto-compile [dir]
266
+
267
+ # Load and display binary peanuts file
268
+ tsk peanuts load config.pnt
269
+ ```
270
+
271
+ ### CSS Commands
272
+ ```bash
273
+ # Expand CSS shortcodes in file
274
+ tsk css expand input.css [output.css]
275
+
276
+ # Show all shortcode → property mappings
277
+ tsk css map
278
+ ```
279
+
280
+ ### AI Commands
281
+ ```bash
282
+ # Query Claude AI with prompt
283
+ tsk ai claude "Explain TuskLang"
284
+
285
+ # Query ChatGPT with prompt
286
+ tsk ai chatgpt "How to use FUJSEN?"
287
+
288
+ # Query custom AI API endpoint
289
+ tsk ai custom https://api.example.com "Hello"
290
+
291
+ # Show current AI configuration
292
+ tsk ai config
293
+
294
+ # Interactive AI API key setup
295
+ tsk ai setup
296
+
297
+ # Test all configured AI connections
298
+ tsk ai test
299
+
300
+ # Get AI-powered auto-completion
301
+ tsk ai complete file.tsk [line] [column]
302
+
303
+ # Analyze file for errors and improvements
304
+ tsk ai analyze file.tsk
305
+
306
+ # Get performance optimization suggestions
307
+ tsk ai optimize file.tsk
308
+
309
+ # Scan for security vulnerabilities
310
+ tsk ai security file.tsk
311
+ ```
312
+
313
+ ### Utility Commands
314
+ ```bash
315
+ # Parse and display TSK file contents
316
+ tsk parse config.tsk
317
+
318
+ # Validate TSK file syntax
319
+ tsk validate config.tsk
320
+
321
+ # Convert between formats
322
+ tsk convert -i input.tsk -o output.tsk
323
+
324
+ # Get specific value by key path
325
+ tsk get config.tsk app.name
326
+
327
+ # Set value by key path
328
+ tsk set config.tsk app.name "New Name"
329
+
330
+ # Show version information
331
+ tsk version
332
+
333
+ # Show help for command
334
+ tsk help [command]
335
+ ```
336
+
337
+ ### Global Options
338
+ ```bash
339
+ # Enable verbose output
340
+ tsk --verbose parse config.tsk
341
+
342
+ # Suppress non-error output
343
+ tsk --quiet parse config.tsk
344
+
345
+ # Output in JSON format
346
+ tsk --json parse config.tsk
347
+
348
+ # Use alternate config file
349
+ tsk --config custom.tsk config get server.port
350
+ ```
351
+
352
+ ## 🚂 Rails Integration
353
+
354
+ ### Application Configuration
355
+ ```ruby
356
+ # config/application.rb
357
+ require 'tusk_lang'
358
+
359
+ class Application < Rails::Application
360
+ # Load TSK configuration
361
+ config_tsk = TuskLang::TSK.from_file(Rails.root.join('config', 'app.tsk'))
362
+
363
+ # Apply settings
364
+ config.app_name = config_tsk.get_value("app", "name")
365
+ config.debug_mode = config_tsk.get_value("app", "debug")
366
+ config.api_key = config_tsk.get_value("api", "key")
367
+ end
368
+ ```
369
+
370
+ ### Dynamic Configuration
371
+ ```ruby
372
+ # config/app.tsk
373
+ [app]
374
+ name = "My Rails App"
375
+ debug = true
376
+
377
+ [api]
378
+ key = "@env('API_KEY')"
379
+ endpoint = "https://api.example.com"
380
+
381
+ [processing]
382
+ transform_fujsen = """
383
+ function transform(data) {
384
+ return {
385
+ processed: true,
386
+ timestamp: new Date().toISOString(),
387
+ data: data.map(item => ({
388
+ id: item.id,
389
+ value: item.value * 2,
390
+ status: 'processed'
391
+ }))
392
+ };
393
+ }
394
+ """
395
+ ```
396
+
397
+ ### Controller Usage
398
+ ```ruby
399
+ # app/controllers/api_controller.rb
400
+ class ApiController < ApplicationController
401
+ def process_data
402
+ config = TuskLang::TSK.from_file(Rails.root.join('config', 'app.tsk'))
403
+
404
+ # Process with FUJSEN
405
+ result = config.execute_fujsen("processing", "transform", params[:data])
406
+
407
+ render json: result
408
+ end
409
+ end
410
+ ```
411
+
412
+ ## 📝 Jekyll Integration
413
+
414
+ ### Site Configuration
415
+ ```ruby
416
+ # _config.tsk
417
+ [site]
418
+ title = "My Jekyll Blog"
419
+ description = "Built with Jekyll and TuskLang"
420
+ url = "https://example.com"
421
+ author = "John Doe"
422
+
423
+ [build]
424
+ destination = "_site"
425
+ plugins = ["jekyll-feed", "jekyll-seo-tag"]
426
+
427
+ [theme]
428
+ name = "minima"
429
+ ```
430
+
431
+ ### Jekyll Plugin
432
+ ```ruby
433
+ # _plugins/tusk_lang.rb
434
+ require 'tusk_lang'
435
+
436
+ module Jekyll
437
+ class TuskLangConfig
438
+ def self.load_config
439
+ config_file = File.join(Dir.pwd, '_config.tsk')
440
+ return {} unless File.exist?(config_file)
441
+
442
+ TuskLang::TSK.from_file(config_file).to_hash
443
+ end
444
+ end
445
+ end
446
+
447
+ # Extend Jekyll configuration
448
+ Jekyll::Hooks.register :site, :after_init do |site|
449
+ tsk_config = Jekyll::TuskLangConfig.load_config
450
+
451
+ # Merge TSK config with Jekyll config
452
+ site.config.merge!(tsk_config)
453
+ end
454
+ ```
455
+
456
+ ### Dynamic Content Generation
457
+ ```ruby
458
+ # _plugins/dynamic_content.rb
459
+ require 'tusk_lang'
460
+
461
+ module Jekyll
462
+ class DynamicContentGenerator < Generator
463
+ safe true
464
+ priority :normal
465
+
466
+ def generate(site)
467
+ config = TuskLang::TSK.from_file(File.join(Dir.pwd, '_config.tsk'))
468
+
469
+ # Generate dynamic pages
470
+ generate_posts(site, config)
471
+ generate_categories(site, config)
472
+ end
473
+
474
+ private
475
+
476
+ def generate_posts(site, config)
477
+ posts_data = config.execute_fujsen("content", "generate_posts")
478
+
479
+ posts_data.each do |post|
480
+ site.pages << Jekyll::Page.new(site, site.source, "_posts", "#{post['date']}-#{post['slug']}.md")
481
+ end
482
+ end
483
+ end
484
+ end
485
+ ```
486
+
487
+ ## 🔧 DevOps Automation
488
+
489
+ ### Deployment Scripts
490
+ ```ruby
491
+ #!/usr/bin/env ruby
492
+ # deploy.rb
493
+
494
+ require 'tusk_lang'
495
+
496
+ # Load deployment configuration
497
+ config = TuskLang::TSK.from_file('deploy.tsk')
498
+
499
+ # Execute deployment logic
500
+ deploy_config = config.execute_fujsen("deploy", "prepare", {
501
+ environment: ENV['RAILS_ENV'],
502
+ branch: ENV['GIT_BRANCH']
503
+ })
504
+
505
+ puts "Deploying to #{deploy_config['target']}..."
506
+ ```
507
+
508
+ ### CI/CD Configuration
509
+ ```ruby
510
+ # .github/workflows/deploy.tsk
511
+ [ci]
512
+ name = "Deploy Application"
513
+ on = ["push"]
514
+
515
+ [jobs]
516
+ build_fujsen = """
517
+ function build() {
518
+ return {
519
+ steps: [
520
+ { name: 'Checkout', uses: 'actions/checkout@v2' },
521
+ { name: 'Setup Ruby', uses: 'ruby/setup-ruby@v1', with: { 'ruby-version': '3.0' } },
522
+ { name: 'Install dependencies', run: 'bundle install' },
523
+ { name: 'Run tests', run: 'bundle exec rspec' },
524
+ { name: 'Deploy', run: 'bundle exec cap production deploy' }
525
+ ]
526
+ };
527
+ }
528
+ """
529
+
530
+ deploy_fujsen = """
531
+ function deploy(environment) {
532
+ return {
533
+ environment: environment,
534
+ steps: [
535
+ { name: 'Deploy to ' + environment, run: 'bundle exec cap ' + environment + ' deploy' }
536
+ ]
537
+ };
538
+ }
539
+ """
540
+ ```
541
+
542
+ ### Infrastructure as Code
543
+ ```ruby
544
+ # infrastructure.tsk
545
+ [aws]
546
+ region = "us-west-2"
547
+ vpc_id = "@env('VPC_ID')"
548
+
549
+ [ec2]
550
+ instance_type = "t3.micro"
551
+ ami_id = "ami-12345678"
552
+
553
+ [deploy]
554
+ deploy_fujsen = """
555
+ function deploy_infrastructure() {
556
+ return {
557
+ steps: [
558
+ { action: 'create_vpc', params: { cidr: '10.0.0.0/16' } },
559
+ { action: 'create_subnet', params: { cidr: '10.0.1.0/24' } },
560
+ { action: 'launch_instance', params: { type: 't3.micro' } }
561
+ ]
562
+ };
563
+ }
564
+ """
565
+ ```
566
+
567
+ ## 🔥 FUJSEN Examples
568
+
569
+ ### Payment Processing Contract
570
+ ```ruby
571
+ contract = TuskLang::TSK.from_string(<<~TSK)
572
+ [contract]
573
+ name = "PaymentProcessor"
574
+ version = "1.0.0"
575
+
576
+ process_fujsen = """
577
+ function process(amount, recipient) {
578
+ if (amount <= 0) throw new Error("Invalid amount");
579
+
580
+ return {
581
+ success: true,
582
+ transactionId: 'tx_' + Date.now(),
583
+ amount: amount,
584
+ recipient: recipient,
585
+ fee: amount * 0.01
586
+ };
587
+ }
588
+ """
589
+
590
+ validate_fujsen = """
591
+ (amount) => amount > 0 && amount <= 1000000
592
+ """
593
+ TSK
594
+
595
+ # Execute payment
596
+ payment = contract.execute_fujsen("contract", "process", 100.50, "alice@example.com")
597
+ is_valid = contract.execute_fujsen("contract", "validate", 500)
598
+ ```
599
+
600
+ ### DeFi Liquidity Pool
601
+ ```ruby
602
+ pool = TuskLang::TSK.from_string(<<~TSK)
603
+ [pool]
604
+ token_a = "FLEX"
605
+ token_b = "USDT"
606
+ reserve_a = 100000
607
+ reserve_b = 50000
608
+
609
+ swap_fujsen = """
610
+ function swap(amountIn, tokenIn) {
611
+ const k = 100000 * 50000;
612
+ const fee = amountIn * 0.003;
613
+ const amountInWithFee = amountIn - fee;
614
+
615
+ if (tokenIn === 'FLEX') {
616
+ const amountOut = (amountInWithFee * 50000) / (100000 + amountInWithFee);
617
+ return {
618
+ amountOut: amountOut,
619
+ fee: fee,
620
+ priceImpact: (amountIn / 100000) * 100
621
+ };
622
+ } else {
623
+ const amountOut = (amountInWithFee * 100000) / (50000 + amountInWithFee);
624
+ return {
625
+ amountOut: amountOut,
626
+ fee: fee,
627
+ priceImpact: (amountIn / 50000) * 100
628
+ };
629
+ }
630
+ }
631
+ """
632
+ TSK
633
+
634
+ # Execute swap
635
+ swap_result = pool.execute_fujsen("pool", "swap", 1000, "FLEX")
636
+ ```
637
+
638
+ ## 🛠️ Advanced Features
639
+
640
+ ### Shell Storage (Binary Format)
641
+ ```ruby
642
+ # Store data in binary format
643
+ data = "Hello, TuskLang!"
644
+ shell_data = TuskLang::ShellStorage.create_shell_data(data, "greeting")
645
+ binary = TuskLang::ShellStorage.pack(shell_data)
646
+
647
+ # Retrieve data
648
+ retrieved = TuskLang::ShellStorage.unpack(binary)
649
+ puts retrieved[:data] # "Hello, TuskLang!"
650
+
651
+ # Detect type
652
+ type = TuskLang::ShellStorage.detect_type(binary)
653
+ puts "Type: #{type}" # "text"
654
+ ```
655
+
656
+ ### Context Injection
657
+ ```ruby
658
+ tsk = TuskLang::TSK.from_string(<<~TSK)
659
+ [processor]
660
+ transform_fujsen = """
661
+ function transform(data) {
662
+ return data.map(item => ({
663
+ ...item,
664
+ processed: true,
665
+ processor: context.processor_name,
666
+ timestamp: new Date().toISOString()
667
+ }));
668
+ }
669
+ """
670
+ TSK
671
+
672
+ context = {
673
+ 'processor_name' => 'Ruby Processor v1.0',
674
+ 'environment' => 'production'
675
+ }
676
+
677
+ result = tsk.execute_fujsen_with_context("processor", "transform", context, data)
678
+ ```
679
+
680
+ ### @ Operator Examples
681
+ ```ruby
682
+ # Database queries
683
+ query = tsk.execute_operators("@Query('users').equalTo('status', 'active').limit(10)")
684
+
685
+ # Caching
686
+ cached = tsk.execute_operators("@cache('5m', 'user_data', userData)")
687
+
688
+ # Metrics
689
+ metrics = tsk.execute_operators("@metrics('api_response_time', 150)")
690
+
691
+ # Conditional logic
692
+ result = tsk.execute_operators("@if(user.isPremium, 'premium', 'standard')")
693
+
694
+ # Date formatting
695
+ timestamp = tsk.execute_operators("@date('%Y-%m-%d %H:%M:%S')")
696
+
697
+ # Environment variables
698
+ api_key = tsk.execute_operators("@env('API_KEY')")
699
+
700
+ # FlexChain operations
701
+ balance = tsk.execute_operators("@flex('balance', '0x123...')")
702
+ transfer = tsk.execute_operators("@flex('transfer', 100, '0x123...', '0x456...')")
703
+ ```
704
+
705
+ ## 📚 TSK Format
706
+
707
+ TSK is a TOML-like format with enhanced features:
708
+
709
+ - **Sections**: `[section_name]`
710
+ - **Key-Value**: `key = value`
711
+ - **Types**: strings, numbers, booleans, arrays, objects, null
712
+ - **Multiline**: Triple quotes `"""`
713
+ - **Comments**: Lines starting with `#`
714
+ - **FUJSEN**: Function serialization in multiline strings
715
+ - **@ Operators**: Intelligence operators for dynamic content
716
+
717
+ ## 🎯 Use Cases
718
+
719
+ 1. **Configuration Files**: Human-readable app configuration
720
+ 2. **Rails Applications**: Application settings and dynamic logic
721
+ 3. **Jekyll Sites**: Static site configuration and content generation
722
+ 4. **DevOps Scripts**: Automation and deployment configuration
723
+ 5. **Smart Contracts**: Store executable code with metadata
724
+ 6. **Data Exchange**: Type-safe data serialization
725
+ 7. **API Definitions**: Function signatures and implementations
726
+ 8. **Workflow Automation**: Scriptable configuration with logic
727
+
728
+ ## 🌟 Why TuskLang Ruby?
729
+
730
+ - **Human-Readable**: Unlike JSON, designed for humans first
731
+ - **Executable**: FUJSEN makes configs programmable
732
+ - **Type-Safe**: No ambiguity in data types
733
+ - **Rails-Ready**: Perfect for Rails applications
734
+ - **Jekyll-Native**: Static site generation support
735
+ - **DevOps-Friendly**: Automation and scripting
736
+ - **Blockchain-Ready**: Perfect for smart contracts
737
+ - **Complete CLI**: Universal command-line interface
738
+ - **Simple**: Minimal syntax, maximum power
739
+
740
+ ## 🔧 Requirements
741
+
742
+ - **Ruby 2.7** or higher
743
+ - **Rails 6.0** or higher (for Rails integration)
744
+ - **Jekyll 4.0** or higher (for Jekyll integration)
745
+
746
+ ## 📄 License
747
+
748
+ Part of the Flexchain project - Blockchain with digital grace.
749
+
750
+ ## 🚀 Getting Started
751
+
752
+ 1. Add `gem 'tusk_lang'` to your Gemfile
753
+ 2. Run `bundle install`
754
+ 3. Start parsing and executing TSK files!
755
+ 4. Explore FUJSEN functions and @ operators
756
+ 5. Use the CLI for development and deployment
757
+ 6. Integrate with Rails or Jekyll as needed
758
+
759
+ The Ruby SDK provides the same powerful features as the JavaScript/TypeScript, Python, and C# SDKs, with native Ruby performance and Rails/Jekyll ecosystem integration, plus a complete CLI implementation.