@nomad-e/bluma-cli 0.1.17 → 0.1.19
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.
- package/README.md +62 -12
- package/dist/config/native_tools.json +7 -0
- package/dist/config/skills/git-commit/LICENSE.txt +18 -0
- package/dist/config/skills/git-commit/SKILL.md +258 -0
- package/dist/config/skills/git-commit/references/REFERENCE.md +249 -0
- package/dist/config/skills/git-commit/scripts/validate_commit_msg.py +163 -0
- package/dist/config/skills/git-pr/LICENSE.txt +18 -0
- package/dist/config/skills/git-pr/SKILL.md +293 -0
- package/dist/config/skills/git-pr/references/REFERENCE.md +256 -0
- package/dist/config/skills/git-pr/scripts/validate_commits.py +112 -0
- package/dist/config/skills/pdf/LICENSE.txt +26 -0
- package/dist/config/skills/pdf/SKILL.md +327 -0
- package/dist/config/skills/pdf/references/FORMS.md +69 -0
- package/dist/config/skills/pdf/references/REFERENCE.md +52 -0
- package/dist/config/skills/pdf/scripts/create_report.py +59 -0
- package/dist/config/skills/pdf/scripts/merge_pdfs.py +39 -0
- package/dist/config/skills/skill-creator/LICENSE.txt +26 -0
- package/dist/config/skills/skill-creator/SKILL.md +229 -0
- package/dist/config/skills/xlsx/LICENSE.txt +18 -0
- package/dist/config/skills/xlsx/SKILL.md +298 -0
- package/dist/config/skills/xlsx/references/REFERENCE.md +337 -0
- package/dist/config/skills/xlsx/scripts/office/__init__.py +2 -0
- package/dist/config/skills/xlsx/scripts/office/__pycache__/__init__.cpython-312.pyc +0 -0
- package/dist/config/skills/xlsx/scripts/office/__pycache__/pack.cpython-312.pyc +0 -0
- package/dist/config/skills/xlsx/scripts/office/__pycache__/soffice.cpython-312.pyc +0 -0
- package/dist/config/skills/xlsx/scripts/office/__pycache__/unpack.cpython-312.pyc +0 -0
- package/dist/config/skills/xlsx/scripts/office/__pycache__/validate.cpython-312.pyc +0 -0
- package/dist/config/skills/xlsx/scripts/office/pack.py +58 -0
- package/dist/config/skills/xlsx/scripts/office/soffice.py +180 -0
- package/dist/config/skills/xlsx/scripts/office/unpack.py +63 -0
- package/dist/config/skills/xlsx/scripts/office/validate.py +122 -0
- package/dist/config/skills/xlsx/scripts/recalc.py +143 -0
- package/dist/main.js +275 -89
- package/package.json +1 -1
- package/dist/config/example.bluma-mcp.json.txt +0 -14
- package/dist/config/models_config.json +0 -78
- package/dist/skills/git-conventional/LICENSE.txt +0 -3
- package/dist/skills/git-conventional/SKILL.md +0 -83
- package/dist/skills/skill-creator/SKILL.md +0 -495
- package/dist/skills/testing/LICENSE.txt +0 -3
- package/dist/skills/testing/SKILL.md +0 -114
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# PDF Forms — Filling and Processing Guide
|
|
2
|
+
|
|
3
|
+
This reference covers PDF form filling using Python and JavaScript libraries.
|
|
4
|
+
|
|
5
|
+
## Detecting Form Fields (Python)
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from pypdf import PdfReader
|
|
9
|
+
|
|
10
|
+
reader = PdfReader("form.pdf")
|
|
11
|
+
fields = reader.get_fields()
|
|
12
|
+
for name, field in fields.items():
|
|
13
|
+
print(f"Field: {name}, Type: {field.get('/FT')}, Value: {field.get('/V')}")
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Filling Forms with pypdf
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from pypdf import PdfReader, PdfWriter
|
|
20
|
+
|
|
21
|
+
reader = PdfReader("form.pdf")
|
|
22
|
+
writer = PdfWriter()
|
|
23
|
+
writer.append(reader)
|
|
24
|
+
|
|
25
|
+
writer.update_page_form_field_values(
|
|
26
|
+
writer.pages[0],
|
|
27
|
+
{
|
|
28
|
+
"name_field": "John Doe",
|
|
29
|
+
"email_field": "john@example.com",
|
|
30
|
+
"date_field": "2026-01-15",
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
with open("filled_form.pdf", "wb") as output:
|
|
35
|
+
writer.write(output)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Filling Forms with pdf-lib (JavaScript)
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
import { PDFDocument } from 'pdf-lib';
|
|
42
|
+
import fs from 'fs';
|
|
43
|
+
|
|
44
|
+
const pdfBytes = fs.readFileSync('form.pdf');
|
|
45
|
+
const pdfDoc = await PDFDocument.load(pdfBytes);
|
|
46
|
+
const form = pdfDoc.getForm();
|
|
47
|
+
|
|
48
|
+
form.getTextField('name').setText('John Doe');
|
|
49
|
+
form.getTextField('email').setText('john@example.com');
|
|
50
|
+
form.getCheckBox('agree').check();
|
|
51
|
+
|
|
52
|
+
const filledBytes = await pdfDoc.save();
|
|
53
|
+
fs.writeFileSync('filled_form.pdf', filledBytes);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Common Form Field Types
|
|
57
|
+
|
|
58
|
+
| Type | pypdf Code | pdf-lib Code |
|
|
59
|
+
|------|-----------|-------------|
|
|
60
|
+
| Text | `update_page_form_field_values` | `getTextField().setText()` |
|
|
61
|
+
| Checkbox | Set to `/Yes` or `/Off` | `getCheckBox().check()` |
|
|
62
|
+
| Radio | Set to option value | `getRadioGroup().select()` |
|
|
63
|
+
| Dropdown | Set to option value | `getDropdown().select()` |
|
|
64
|
+
|
|
65
|
+
## Tips
|
|
66
|
+
|
|
67
|
+
- Always flatten forms after filling if the PDF will be shared (prevents editing).
|
|
68
|
+
- Some PDFs have XFA forms (XML-based) which are harder to fill programmatically.
|
|
69
|
+
- For XFA forms, consider using pdftk or a commercial library.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# PDF Processing — Advanced Reference
|
|
2
|
+
|
|
3
|
+
This document covers advanced PDF processing techniques beyond the basics in SKILL.md.
|
|
4
|
+
|
|
5
|
+
## pypdfium2 — High-Performance Rendering
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
import pypdfium2 as pdfium
|
|
9
|
+
|
|
10
|
+
pdf = pdfium.PdfDocument("document.pdf")
|
|
11
|
+
for i, page in enumerate(pdf):
|
|
12
|
+
bitmap = page.render(scale=2)
|
|
13
|
+
image = bitmap.to_pil()
|
|
14
|
+
image.save(f"page_{i+1}.png")
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## JavaScript Libraries (pdf-lib)
|
|
18
|
+
|
|
19
|
+
For browser-based or Node.js PDF manipulation:
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
import { PDFDocument } from 'pdf-lib';
|
|
23
|
+
|
|
24
|
+
const pdfDoc = await PDFDocument.create();
|
|
25
|
+
const page = pdfDoc.addPage([600, 400]);
|
|
26
|
+
page.drawText('Hello, PDF!', { x: 50, y: 350, size: 30 });
|
|
27
|
+
const pdfBytes = await pdfDoc.save();
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## pdf-lib — Modify Existing PDFs
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
import { PDFDocument } from 'pdf-lib';
|
|
34
|
+
import fs from 'fs';
|
|
35
|
+
|
|
36
|
+
const existingPdfBytes = fs.readFileSync('input.pdf');
|
|
37
|
+
const pdfDoc = await PDFDocument.load(existingPdfBytes);
|
|
38
|
+
const pages = pdfDoc.getPages();
|
|
39
|
+
const firstPage = pages[0];
|
|
40
|
+
firstPage.drawText('WATERMARK', { x: 200, y: 400, size: 50, opacity: 0.3 });
|
|
41
|
+
const pdfBytes = await pdfDoc.save();
|
|
42
|
+
fs.writeFileSync('output.pdf', pdfBytes);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Troubleshooting
|
|
46
|
+
|
|
47
|
+
| Issue | Solution |
|
|
48
|
+
|-------|----------|
|
|
49
|
+
| "PdfReadError: EOF marker not found" | File is corrupted or not a valid PDF |
|
|
50
|
+
| Empty text extraction | PDF might be image-based; use OCR (pytesseract) |
|
|
51
|
+
| Tables not extracted correctly | Adjust pdfplumber table settings or try camelot |
|
|
52
|
+
| Large PDF processing slow | Process pages in chunks or use pypdfium2 |
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Create a simple PDF report from CSV data using reportlab.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
python create_report.py --input data.csv --output ./artifacts/report.pdf
|
|
6
|
+
python create_report.py --input data.csv --output report.pdf --title "Sales Report Q1 2026"
|
|
7
|
+
"""
|
|
8
|
+
import argparse
|
|
9
|
+
import csv
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
def create_report(input_csv: str, output_pdf: str, title: str = "Report") -> None:
|
|
13
|
+
try:
|
|
14
|
+
from reportlab.lib.pagesizes import A4
|
|
15
|
+
from reportlab.lib import colors
|
|
16
|
+
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
|
|
17
|
+
from reportlab.lib.styles import getSampleStyleSheet
|
|
18
|
+
except ImportError:
|
|
19
|
+
print("Error: reportlab is required. Install with: pip install reportlab", file=sys.stderr)
|
|
20
|
+
sys.exit(1)
|
|
21
|
+
|
|
22
|
+
with open(input_csv, "r", encoding="utf-8") as f:
|
|
23
|
+
reader = csv.reader(f)
|
|
24
|
+
data = list(reader)
|
|
25
|
+
|
|
26
|
+
if not data:
|
|
27
|
+
print("Error: CSV file is empty", file=sys.stderr)
|
|
28
|
+
sys.exit(1)
|
|
29
|
+
|
|
30
|
+
doc = SimpleDocTemplate(output_pdf, pagesize=A4)
|
|
31
|
+
styles = getSampleStyleSheet()
|
|
32
|
+
elements = []
|
|
33
|
+
|
|
34
|
+
elements.append(Paragraph(title, styles["Title"]))
|
|
35
|
+
elements.append(Spacer(1, 20))
|
|
36
|
+
|
|
37
|
+
table = Table(data)
|
|
38
|
+
table.setStyle(TableStyle([
|
|
39
|
+
("BACKGROUND", (0, 0), (-1, 0), colors.grey),
|
|
40
|
+
("TEXTCOLOR", (0, 0), (-1, 0), colors.whitesmoke),
|
|
41
|
+
("ALIGN", (0, 0), (-1, -1), "CENTER"),
|
|
42
|
+
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
|
43
|
+
("FONTSIZE", (0, 0), (-1, 0), 12),
|
|
44
|
+
("BOTTOMPADDING", (0, 0), (-1, 0), 12),
|
|
45
|
+
("BACKGROUND", (0, 1), (-1, -1), colors.beige),
|
|
46
|
+
("GRID", (0, 0), (-1, -1), 1, colors.black),
|
|
47
|
+
]))
|
|
48
|
+
elements.append(table)
|
|
49
|
+
|
|
50
|
+
doc.build(elements)
|
|
51
|
+
print(f"Report created: {output_pdf} ({len(data)-1} data rows)")
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
parser = argparse.ArgumentParser(description="Create PDF report from CSV")
|
|
55
|
+
parser.add_argument("--input", "-i", required=True, help="Input CSV file")
|
|
56
|
+
parser.add_argument("--output", "-o", required=True, help="Output PDF path")
|
|
57
|
+
parser.add_argument("--title", "-t", default="Report", help="Report title")
|
|
58
|
+
args = parser.parse_args()
|
|
59
|
+
create_report(args.input, args.output, args.title)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Merge multiple PDF files into a single output PDF.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
python merge_pdfs.py --output merged.pdf file1.pdf file2.pdf file3.pdf
|
|
6
|
+
python merge_pdfs.py --output ./artifacts/combined.pdf *.pdf
|
|
7
|
+
"""
|
|
8
|
+
import argparse
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
def merge_pdfs(input_files: list[str], output_path: str) -> None:
|
|
12
|
+
try:
|
|
13
|
+
from pypdf import PdfWriter, PdfReader
|
|
14
|
+
except ImportError:
|
|
15
|
+
print("Error: pypdf is required. Install with: pip install pypdf", file=sys.stderr)
|
|
16
|
+
sys.exit(1)
|
|
17
|
+
|
|
18
|
+
writer = PdfWriter()
|
|
19
|
+
for pdf_file in input_files:
|
|
20
|
+
try:
|
|
21
|
+
reader = PdfReader(pdf_file)
|
|
22
|
+
for page in reader.pages:
|
|
23
|
+
writer.add_page(page)
|
|
24
|
+
print(f"Added: {pdf_file} ({len(reader.pages)} pages)")
|
|
25
|
+
except Exception as e:
|
|
26
|
+
print(f"Error reading {pdf_file}: {e}", file=sys.stderr)
|
|
27
|
+
sys.exit(1)
|
|
28
|
+
|
|
29
|
+
with open(output_path, "wb") as f:
|
|
30
|
+
writer.write(f)
|
|
31
|
+
|
|
32
|
+
print(f"Merged {len(input_files)} files -> {output_path}")
|
|
33
|
+
|
|
34
|
+
if __name__ == "__main__":
|
|
35
|
+
parser = argparse.ArgumentParser(description="Merge PDF files")
|
|
36
|
+
parser.add_argument("files", nargs="+", help="PDF files to merge")
|
|
37
|
+
parser.add_argument("--output", "-o", required=True, help="Output file path")
|
|
38
|
+
args = parser.parse_args()
|
|
39
|
+
merge_pdfs(args.files, args.output)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
© 2026 NomadEngenuity LDA. All rights reserved.
|
|
2
|
+
|
|
3
|
+
LICENSE: Use of these materials (including all code, prompts, assets, files,
|
|
4
|
+
and other components of this Skill) is governed by your agreement with
|
|
5
|
+
NomadEngenuity LDA regarding use of NomadEngenuity LDA's services. If no
|
|
6
|
+
separate agreement exists, use is governed by NomadEngenuity LDA's applicable
|
|
7
|
+
Terms of Service.
|
|
8
|
+
|
|
9
|
+
ADDITIONAL RESTRICTIONS: Notwithstanding anything in the Agreement to the
|
|
10
|
+
contrary, users may not:
|
|
11
|
+
|
|
12
|
+
- Extract these materials from the Services or retain copies of these
|
|
13
|
+
materials outside the Services
|
|
14
|
+
- Reproduce or copy these materials, except for temporary copies created
|
|
15
|
+
automatically during authorized use of the Services
|
|
16
|
+
- Create derivative works based on these materials
|
|
17
|
+
- Distribute, sublicense, or transfer these materials to any third party
|
|
18
|
+
- Make, offer to sell, sell, or import any inventions embodied in these
|
|
19
|
+
materials
|
|
20
|
+
- Reverse engineer, decompile, or disassemble these materials
|
|
21
|
+
|
|
22
|
+
The receipt, viewing, or possession of these materials does not convey or
|
|
23
|
+
imply any license or right beyond those expressly granted above.
|
|
24
|
+
|
|
25
|
+
NomadEngenuity LDA retains all right, title, and interest in these materials,
|
|
26
|
+
including all copyrights, patents, and other intellectual property rights.
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-creator
|
|
3
|
+
description: >
|
|
4
|
+
Use this skill when the user wants to create, write, build, or author a new
|
|
5
|
+
BluMa skill. Triggers include: "create a skill", "make a new skill",
|
|
6
|
+
"build a skill for X", "I need a skill that does Y", "skill template",
|
|
7
|
+
or any request to package knowledge/workflows as a reusable skill module.
|
|
8
|
+
license: Proprietary. LICENSE.txt has complete terms
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Instructions
|
|
12
|
+
|
|
13
|
+
## Context
|
|
14
|
+
You are a Skill Builder. You create new BluMa skills with the full Progressive Disclosure structure. Every skill you create MUST follow the standard layout.
|
|
15
|
+
|
|
16
|
+
## Standard Skill Layout
|
|
17
|
+
|
|
18
|
+
Every skill is a directory with this structure:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
skill-name/
|
|
22
|
+
SKILL.md # Core instructions (Level 2)
|
|
23
|
+
LICENSE.txt # License terms
|
|
24
|
+
references/ # Additional docs loaded on-demand (Level 3a)
|
|
25
|
+
REFERENCE.md # Advanced guide (if applicable)
|
|
26
|
+
scripts/ # Ready-made scripts (Level 3b)
|
|
27
|
+
(domain-relevant scripts)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The 3 levels of Progressive Disclosure:
|
|
31
|
+
- **Level 1**: `description` in frontmatter — always visible in the skills list, acts as a trigger
|
|
32
|
+
- **Level 2**: Body of SKILL.md — loaded when the skill is activated via `load_skill`
|
|
33
|
+
- **Level 3**: `references/` and `scripts/` — accessed only when the task requires them
|
|
34
|
+
|
|
35
|
+
## Procedure
|
|
36
|
+
|
|
37
|
+
### Step 1: Ask Location (REQUIRED)
|
|
38
|
+
|
|
39
|
+
Before anything else, ask the user where to create the skill:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
message({
|
|
43
|
+
content: "Where should I create this skill?\n\n**1. Project** (`.bluma/skills/`) - Only available in THIS project\n**2. Global** (`~/.bluma/skills/`) - Available in ALL projects\n\nChoose 1 or 2:",
|
|
44
|
+
message_type: "result"
|
|
45
|
+
})
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Wait for user response before continuing.
|
|
49
|
+
|
|
50
|
+
### Step 2: Analyze User Input
|
|
51
|
+
|
|
52
|
+
Extract from user's content:
|
|
53
|
+
- Purpose/domain
|
|
54
|
+
- Responsibilities and workflows
|
|
55
|
+
- Rules/constraints
|
|
56
|
+
- Error scenarios
|
|
57
|
+
- Whether the content is short (<100 lines) or extensive (>100 lines)
|
|
58
|
+
|
|
59
|
+
### Step 3: Generate Skill Name
|
|
60
|
+
|
|
61
|
+
Create kebab-case name from domain:
|
|
62
|
+
- "git workflow" -> `git-workflow`
|
|
63
|
+
- "api testing" -> `api-testing`
|
|
64
|
+
- "pdf processing" -> `pdf`
|
|
65
|
+
|
|
66
|
+
### Step 4: Determine Path
|
|
67
|
+
|
|
68
|
+
Based on user's choice in Step 1:
|
|
69
|
+
- **Project (1)**: `.bluma/skills/{name}/`
|
|
70
|
+
- **Global (2)**: `~/.bluma/skills/{name}/`
|
|
71
|
+
|
|
72
|
+
### Step 5: Check Directory
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
ls_tool({ path: "{chosen-path}/{name}" })
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Verify directory doesn't exist (or confirm overwrite with user).
|
|
79
|
+
|
|
80
|
+
### Step 6: Plan Content Split
|
|
81
|
+
|
|
82
|
+
Decide what goes where based on content size:
|
|
83
|
+
|
|
84
|
+
**If content is SHORT (<100 lines):**
|
|
85
|
+
- Everything goes in SKILL.md body
|
|
86
|
+
- references/ gets a minimal REFERENCE.md placeholder
|
|
87
|
+
- scripts/ stays empty (or gets a single utility script if applicable)
|
|
88
|
+
|
|
89
|
+
**If content is EXTENSIVE (>100 lines):**
|
|
90
|
+
- SKILL.md body gets: overview, quick start, core procedure (the essentials)
|
|
91
|
+
- references/ gets: advanced docs, detailed API guides, specialized topics
|
|
92
|
+
- scripts/ gets: reusable scripts the agent can execute
|
|
93
|
+
|
|
94
|
+
### Step 7: Create the Skill Structure
|
|
95
|
+
|
|
96
|
+
Create the following files in order:
|
|
97
|
+
|
|
98
|
+
**7a. Create SKILL.md**
|
|
99
|
+
|
|
100
|
+
Use `edit_tool` with this template:
|
|
101
|
+
|
|
102
|
+
```markdown
|
|
103
|
+
---
|
|
104
|
+
name: {kebab-case-name}
|
|
105
|
+
description: >
|
|
106
|
+
Use this skill for any task involving {domain}. Triggers include: {list
|
|
107
|
+
of trigger phrases and keywords that should activate this skill}. Use
|
|
108
|
+
this skill whenever the user mentions {key terms} or any {domain}-related
|
|
109
|
+
task.
|
|
110
|
+
license: Proprietary. LICENSE.txt has complete terms
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
# {Domain} Guide
|
|
114
|
+
|
|
115
|
+
## Overview
|
|
116
|
+
|
|
117
|
+
{Brief description of what this skill covers and when to use it.}
|
|
118
|
+
{If extensive content exists in references/, mention it here:}
|
|
119
|
+
{For advanced features, see references/REFERENCE.md.}
|
|
120
|
+
|
|
121
|
+
## Quick Start
|
|
122
|
+
|
|
123
|
+
{Minimal example to get started — 5-10 lines max.}
|
|
124
|
+
|
|
125
|
+
## Procedure
|
|
126
|
+
|
|
127
|
+
### Step 1: {First Action}
|
|
128
|
+
{Instructions}
|
|
129
|
+
|
|
130
|
+
### Step 2: {Second Action}
|
|
131
|
+
{Instructions}
|
|
132
|
+
|
|
133
|
+
## Error Reference
|
|
134
|
+
|
|
135
|
+
| Error | Cause | Fix |
|
|
136
|
+
|-------|-------|-----|
|
|
137
|
+
| {error} | {cause} | {fix} |
|
|
138
|
+
|
|
139
|
+
## Available References
|
|
140
|
+
|
|
141
|
+
{List each reference file with when to use it:}
|
|
142
|
+
- REFERENCE.md: For advanced features and detailed API docs
|
|
143
|
+
{Add more as needed}
|
|
144
|
+
|
|
145
|
+
## Available Scripts
|
|
146
|
+
|
|
147
|
+
{List each script with what it does:}
|
|
148
|
+
- {script_name.py}: {one-line description}
|
|
149
|
+
{Or "No scripts available for this skill." if none}
|
|
150
|
+
|
|
151
|
+
## Next Steps
|
|
152
|
+
|
|
153
|
+
{Point to references/ for advanced topics.}
|
|
154
|
+
{Point to scripts/ for automation.}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**7b. Create LICENSE.txt**
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
edit_tool({
|
|
161
|
+
file_path: "{path}/{name}/LICENSE.txt",
|
|
162
|
+
old_string: "",
|
|
163
|
+
new_string: "© 2026 NomadEngenuity LDA. All rights reserved.\n\nLICENSE: Use of these materials..."
|
|
164
|
+
})
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Use the standard NomadEngenuity proprietary license (same as other native skills).
|
|
168
|
+
|
|
169
|
+
**7c. Create references/REFERENCE.md**
|
|
170
|
+
|
|
171
|
+
If extensive content exists, put advanced documentation here.
|
|
172
|
+
If content is short, create a placeholder:
|
|
173
|
+
|
|
174
|
+
```markdown
|
|
175
|
+
# {Domain} — Advanced Reference
|
|
176
|
+
|
|
177
|
+
{Advanced documentation, detailed examples, specialized topics.}
|
|
178
|
+
{This file is loaded on-demand when the task requires deeper knowledge.}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**7d. Create scripts/ (if applicable)**
|
|
182
|
+
|
|
183
|
+
If the domain benefits from ready-made scripts, create them.
|
|
184
|
+
Each script should:
|
|
185
|
+
- Be self-contained and executable with `python script.py [args]`
|
|
186
|
+
- Include a docstring explaining what it does
|
|
187
|
+
- Accept arguments via argparse or sys.argv
|
|
188
|
+
- Print results to stdout or write to a specified output path
|
|
189
|
+
|
|
190
|
+
Example script header:
|
|
191
|
+
```python
|
|
192
|
+
"""
|
|
193
|
+
{description of what this script does}
|
|
194
|
+
|
|
195
|
+
Usage:
|
|
196
|
+
python {script_name}.py --input data.csv --output ./artifacts/result.pdf
|
|
197
|
+
"""
|
|
198
|
+
import argparse
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Step 8: Report Result
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
message({
|
|
205
|
+
content: "Skill **{name}** created at `{path}/{name}/`\n\nStructure:\n- SKILL.md (core instructions)\n- LICENSE.txt\n- references/REFERENCE.md\n- scripts/ {list or empty}\n\nLocation: {Project|Global}\nThe skill is now available and will appear in the skills list.",
|
|
206
|
+
message_type: "result"
|
|
207
|
+
})
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Location Reference
|
|
211
|
+
|
|
212
|
+
| Location | Path | Scope | Use When |
|
|
213
|
+
|----------|------|-------|----------|
|
|
214
|
+
| Project | `.bluma/skills/` | This project only | Skill is specific to this codebase |
|
|
215
|
+
| Global | `~/.bluma/skills/` | All projects | Skill is generic and reusable |
|
|
216
|
+
|
|
217
|
+
## Guidelines
|
|
218
|
+
|
|
219
|
+
- ALWAYS ask location first with `message_type: "result"`
|
|
220
|
+
- ALWAYS create the full structure: SKILL.md + LICENSE.txt + references/ + scripts/
|
|
221
|
+
- The `description` field is CRITICAL — it is the only text always visible and determines when the skill is activated. Include trigger words and phrases.
|
|
222
|
+
- SKILL.md body should contain only the essentials (quick start + procedure). Advanced docs go in references/.
|
|
223
|
+
- Scripts should be self-contained, executable, and well-documented.
|
|
224
|
+
- Use lists not tables where possible (saves tokens)
|
|
225
|
+
- No emojis in skill content
|
|
226
|
+
- English only for skill content (translate user input if needed)
|
|
227
|
+
- Professional, specific language
|
|
228
|
+
- Extract ALL information from user input
|
|
229
|
+
- NEVER create a skill with the same name as a native BluMa skill (check available_skills list first)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
BluMa — Base Language Unit · Model Agent
|
|
2
|
+
Proprietary License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2024-2026 BluMa Contributors
|
|
5
|
+
|
|
6
|
+
This skill is part of the BluMa CLI distribution.
|
|
7
|
+
It is provided as a bundled native skill and may not be
|
|
8
|
+
redistributed, modified, or used outside of the BluMa agent
|
|
9
|
+
framework without prior written permission.
|
|
10
|
+
|
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
12
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
13
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
14
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
15
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
16
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
17
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
18
|
+
OTHER DEALINGS IN THE SOFTWARE.
|