← 返回 Skills 市场
fredguile

Lynx Skill

作者 Fred Ghilini · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ⚠ suspicious
33
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install lynx-skill
功能描述
Stateless Go CLI for the Lynx Reservations (www.lynx-reservations.com) travel agency system. Use this skill whenever the user needs to search files, retrieve...
使用说明 (SKILL.md)

lynx-skill

Stateless Go CLI that replicates every tool from lynx-mcp-server as standalone commands — no daemon, no SSE, no Bearer token.

Quick Install

cd lynx-travel-agent/lynx-skill
go build -o bin/lynx .
# optional: put it in PATH
cp bin/lynx ~/bin/lynx   # or /usr/local/bin/

Credentials

The binary reads these environment variables. All three are required:

Variable Description
LYNX_USERNAME Lynx username
LYNX_PASSWORD Lynx password
LYNX_COMPANY_CODE Company code

Available Commands

# Command Description
1 file-search-by-party-name Search files by customer last name
2 file-search-by-file-reference Search files by Lynx file reference
3 retrieve-itinerary Get detailed itinerary for a file
4 retrieve-file-documents Get documents for a transaction
5 attachment-upload Upload a file attachment from disk
6 file-document-save Save document at the file level
7 transaction-document-save Save document at the transaction level

All commands output JSON to stdout. Errors go to stderr. Exit code 0 = success, 1 = failure.


1. file-search-by-party-name

Search for files by the customer's last name.

lynx file-search-by-party-name --party-name=LASTNAME

Flags:

Flag Type Required Description
--party-name` string yes Customer last name to search for

Output:

{
  "count": 1,
  "results": [
    {
      "companyCode": "XX",
      "clientIdentifier": "12345",
      "clientReference": "REF-ABC",
      "currency": "EUR",
      "fileIdentifier": "12345",
      "fileReference": "FTXXXXXXXXX",
      "partyName": "SMITH",
      "status": "Active",
      "travelDate": "2026-06-15"
    }
  ]
}

Examples:

lynx file-search-by-party-name --party-name=Smith
lynx file-search-by-party-name --party-name=Smi

2. file-search-by-file-reference

Search for a file using its Lynx file reference (e.g. FTXXXXXXXXX).

lynx file-search-by-file-reference --file-reference=FTXXXXXXXXX

Flags:

Flag Type Required Description
--file-reference string yes Lynx file reference

Output: Same JSON structure as file-search-by-party-name (count + results array).

Example:

lynx file-search-by-file-reference --file-reference=FT16476987

3. retrieve-itinerary

Get the full itinerary for a given file.

lynx retrieve-itinerary --file-identifier=ID

Flags:

Flag Short Type Required Default Description
--file-identifier -f string yes Numeric file identifier (from search results)
--show-cancelled -c bool no false Include cancelled bookings in the results

Output:

{
  "type": "...",
  "partyName": "SMITH",
  "fileReference": "FTXXXXXXXXX",
  "fileIdentifier": "12345",
  "clientIdentifier": "12345",
  "agentReference": "AGT001",
  "itineraryCount": 2,
  "itineraries": [
    {
      "voucherIdentifier": "V123",
      "date": "15 Jun 2026",
      "transactionIdentifier": "btx12345",
      "supplier": "Hotel ABC",
      "status": "Confirmed",
      "confirmationNumber": "CONF-001",
      "location": "Paris"
    }
  ]
}

Examples:

# Active bookings only (default)
lynx retrieve-itinerary --file-identifier=16476987

# Include cancelled bookings
lynx retrieve-itinerary --file-identifier=16476987 --show-cancelled

4. retrieve-file-documents

Retrieve all documents associated with a specific transaction within a file.

lynx retrieve-file-documents \
  --file-identifier=ID \
  --transaction-identifier=TXID

Flags:

Flag Type Required Description
--file-identifier string yes Numeric file identifier
--transaction-identifier string yes Transaction identifier (from itinerary)

Output:

{
  "count": 1,
  "results": [
    {
      "fileIdentifier": "12345",
      "transactionIdentifier": "btx12345",
      "documentIdentifier": "doc_001",
      "documentName": "Invoice",
      "documentType": "SUPP",
      "content": "\x3Cspan>Invoice details\x3C/span>",
      "attachmentUrl": "/documents/file/f16476987/d20250709064401.pdf"
    }
  ]
}

Example:

lynx retrieve-file-documents \
  --file-identifier=16476987 \
  --transaction-identifier=btx12345

5. attachment-upload

Upload a file (PDF, image, etc.) from disk and associate it with a document.

lynx attachment-upload \
  --identifier=FILEID \
  --file=/path/to/document.pdf

Flags:

Flag Type Required Description
--identifier string yes Unique identifier for the attachment
--file string yes Path to the file on disk

Output:

{
  "attachmentUrl": "/documents/file/f16476987/d20250709064401.pdf"
}

The returned attachmentUrl can be passed to file-document-save or transaction-document-save as --attachment-url.

Examples:

lynx attachment-upload --identifier=f16476987 --file=./documents/invoice.pdf
lynx attachment-upload --identifier=f16476987 --file=./documents/receipt.jpg

6. file-document-save

Save (create or update) a document at the file level.

lynx file-document-save \
  --file-identifier=ID \
  --name=NAME \
  --content=CONTENT \
  --type=TYPE \
  [--attachment-url=URL]

Flags:

Flag Type Required Description
--file-identifier string yes Numeric file identifier
--name string yes Document name
--content string yes Document content (plain text or HTML)
--type string yes Document type code — see valid values below
--attachment-url string no Attachment URL from attachment-upload

Valid --type values:

Code Display Name
SUPP Supplier Communication
CLINT Agent Communication
GEN General
INV Accounting Communication
AFTER After Hours Phone Inquiry
EMAIL Email
FLIGH Flight Information
BOOKI Mail Merge Document
PHONE Phone Conversation
CLCOM Travelling Client Communication

⚠️ Only these exact codes are accepted. Passing an invalid code will be rejected before the request is sent. The documentType field returned by retrieve-file-documents is the internal code (e.g. SUPP), which can be passed directly to --type.

Output:

{
  "status": "ok"
}

Examples:

lynx file-document-save \
  --file-identifier=16476987 \
  --name="Note" \
  --content="Customer requested change of date" \
  --type=SUPP

lynx file-document-save \
  --file-identifier=16476987 \
  --name="Invoice" \
  --content="\x3Cspan>Invoice #1234 — 1500.00 EUR\x3C/span>" \
  --type=INV \
  --attachment-url=/documents/file/f16476987/d20250709064401.pdf

7. transaction-document-save

Save (create or update) a document at the transaction level.

lynx transaction-document-save \
  --file-identifier=ID \
  --transaction-identifier=TXID \
  --name=NAME \
  --content=CONTENT \
  --type=TYPE \
  [--attachment-url=URL]

Flags:

Flag Type Required Description
--file-identifier string yes Numeric file identifier
--transaction-identifier string yes Transaction identifier
--name string yes Document name
--content string yes Document content (plain text or HTML)
--type string yes Document type code — see valid values in file-document-save
--attachment-url string no Attachment URL from attachment-upload

Output:

{
  "status": "ok"
}

Examples:

lynx transaction-document-save \
  --file-identifier=16476987 \
  --transaction-identifier=btx12345 \
  --name="Voucher" \
  --content="Confirmation voucher for hotel booking" \
  --type=SUPP

lynx transaction-document-save \
  --file-identifier=16476987 \
  --transaction-identifier=btx12345 \
  --name="Invoice" \
  --content="\x3Cb>Paid: 500 EUR\x3C/b>" \
  --type=INV \
  --attachment-url=/documents/file/f16476987/d20250709064401.pdf

SAMPLES — Multi-Step Workflows

Sample 1: Find a customer file, inspect itinerary, save a note

# Step 1 — Search by customer last name
lynx file-search-by-party-name --party-name=Smith

# Step 2 — From the results, grab the fileIdentifier (e.g. 16476987)
#          and inspect the itinerary
lynx retrieve-itinerary --file-identifier=16476987

# Step 3 — From the itinerary, get a transactionIdentifier (e.g. btx12345)
#          and save a note at transaction level
lynx transaction-document-save \
  --file-identifier=16476987 \
  --transaction-identifier=btx12345 \
  --name="Note" \
  --content="Customer requested date change" \
  --type=SUPP

Sample 2: Upload an invoice and attach it to a file

# Step 1 — Search file by reference
lynx file-search-by-file-reference --file-reference=FT16476987

# Step 2 — Upload the invoice PDF from disk
lynx attachment-upload \
  --identifier=f16476987 \
  --file=./invoices/invoice_1234.pdf

# Step 3 — Save the document at file level with the attachment URL
lynx file-document-save \
  --file-identifier=16476987 \
  --name="Invoice #1234" \
  --content="\x3Cspan>Invoice 1234 — 1500 EUR\x3C/span>" \
  --type=INVOICE \
  --attachment-url=/documents/file/f16476987/d20250709064401.pdf

Sample 3: Retrieve documents, check content, save a new receipt

# Step 1 — Retrieve all documents for a transaction
lynx retrieve-file-documents \
  --file-identifier=16476987 \
  --transaction-identifier=btx12345

# Step 2 — Pipe the JSON output through jq to inspect document names
lynx retrieve-file-documents \
  --file-identifier=16476987 \
  --transaction-identifier=btx12345 \
  | jq '.results[].documentName'

# Step 3 — Upload a payment receipt
lynx attachment-upload \
  --identifier=f16476987 \
  --file=./receipts/payment_receipt.pdf

# Step 4 — Save the receipt at transaction level
lynx transaction-document-save \
  --file-identifier=16476987 \
  --transaction-identifier=btx12345 \
  --name="Payment Receipt" \
  --content="\x3Cb>Paid: 500 EUR on 01-Jun-2026\x3C/b>" \
  --type=RECEIPT \
  --attachment-url=/documents/file/f16476987/d20250709064401.pdf

Sample 4: Full document management lifecycle

# 1. Find the file
lynx file-search-by-party-name --party-name=Smith

# 2. Get the itinerary (find transaction identifiers)
lynx retrieve-itinerary --file-identifier=16476987

# 3. Upload an attachment
lynx attachment-upload \
  --identifier=f16476987 \
  --file=./invoice.pdf

# 4. Save the document at file level
lynx file-document-save \
  --file-identifier=16476987 \
  --name="Invoice" \
  --content="\x3Cspan>See attached PDF\x3C/span>" \
  --type=SUPP \
  --attachment-url=/documents/file/f16476987/d20250709064401.pdf

# 5. Verify the document was saved by retrieving all documents
lynx retrieve-file-documents \
  --file-identifier=16476987 \
  --transaction-identifier=btx12345

Troubleshooting

Symptom Likely Cause
authentication failed Missing or invalid LYNX_* env vars
LYNX_USERNAME is not set Environment variable not defined
invalid partyName argument Missing --party-name flag
invalid file reference argument Missing --file-reference flag
failed to parse response GWT-RPC format changed or invalid identifier
unexpected response format Attachment upload was rejected (check file size)
exit code 1, no stdout Error written to stderr; run lynx \x3Ccommand> 2>&1 to inspect

Quick debug recipes

# Capture stderr
lynx file-search-by-party-name --party-name=Smith 2>&1

# Pretty-print JSON
lynx file-search-by-party-name --party-name=Smith | jq

# Extract specific field
lynx file-search-by-party-name --party-name=Smith | jq '.results[].fileIdentifier'

# Check env vars are set
env | grep LYNX

Architecture

lynx-skill/
├── main.go                     # Entry point — calls cmd.Run()
├── go.mod                      # Module: dodmcdund.cc/lynx-travel-agent/lynxskill (Go 1.23.10)
├── .gitignore                  # Ignores /bin/, /lynxskill, .env
├── SKILL.md                    # This file — OpenClaw skill definition
├── README.md                   # User-facing documentation
├── lynx_architecture.md        # Full architecture document (decisions, comparisons)
│
├── cmd/                        # CLI commands — one file per command + dispatcher
│   ├── cmd.go                  # Command registry, dispatcher, .env auto-loader, config
│   ├── file_search_by_party_name.go
│   ├── file_search_by_file_reference.go
│   ├── retrieve_itinerary.go
│   ├── retrieve_file_documents.go
│   ├── attachment_upload.go
│   ├── file_document_save.go
│   └── transaction_document_save.go
│
├── gwt/                        # GWT-RPC protocol layer
│   ├── types.go                # GWT type constants (class names)
│   ├── build.go                # GWT-RPC body builders (one func per action)
│   ├── parse.go                # GWT response parsers + response structs
│   └── parse_test.go           # Parser tests (10-result FileSearchResponse)
│
└── lynx/                       # HTTP client layer
    ├── auth.go                 # GWT-RPC login → JSESSIONID + http.Client with cookiejar
    └── client.go               # HTTP helpers: DoGWTRequest, DoMultipartRequest, GWT error parse

Lessons from Implementation (AP-17)

1. GWT-RPC Requires Two Parsers

The Lynx backend returns two GWT-RPC serialization formats. The parser auto-detects:

  • Old format (pre-mid 2025): Type strings like com.lynxtraveltech.client.shared.model.FileSearchResponse/2457361185 appear directly in the data array. The parser walks backward from the end of the parsed array, mapping indices to values.
  • Lazy serialization (current): Type strings are resolved through index-based references. The first mapped string in the data array determines which format is active.

The ParseFileSearchResponse function uses backward scanning: it iterates from the last element backward, identifies FileSearchResults type markers, and extracts 10 fields per result. This approach correctly handles multi-result responses (tested with 10 results in parse_test.go).

2. .env Auto-Load (Convenience vs Security)

cmd/cmd.go:13-33 implements a lightweight .env loader — no external dependency. It reads .env from the working directory at startup:

  • Lines are split on =, whitespace-trimmed
  • Only sets env vars that are not already set (env vars take precedence)
  • Silently returns if .env doesn't exist

.gitignore already includes .env to prevent credential leaks. If .env exists with real credentials, it will be ignored by git. This resolves the "ACTION REQUIRED" item from the initial architecture.

3. No Retry/Backoff (Deferred)

The MCP server implements exponential backoff retry (0s → 5s → 10s → 30s → 30s, max 5 attempts) with RetryHTTPRequest. The CLI does not implement retry yet. Rationale:

  • CLI is designed for agent use (one-shot commands), not high-throughput automation
  • If 429 or transient failures are observed in practice, add a simple retry wrapper in lynx/client.go

4. Attachment Upload — Consolidated Parsing

The MCP server has duplicated parseResponseBody functions in pkg/tools/attachment_upload.go:155 and pkg/rest/attachment_upload.go:146. The CLI consolidates this into a single parseAttachmentResponse in cmd/attachment_upload.go:84-101.

The Lynx backend returns SUCCESS:/path/to/file: (colon-delimited). The parser:

  1. Strips SUCCESS: prefix
  2. Trims trailing colon and whitespace
  3. Validates the result starts with /

5. MCP Identifier Typo Corrected

The MCP server parameter is named identifer (missing 'i', consistent throughout the codebase). The CLI parameter correctly uses --identifier. This is a breaking change from the MCP naming but fixes the original typo.

6. Test Coverage

gwt/parse_test.go contains a parser test with a real GWT-RPC response for file-search-by-party-name ("BRAY" search yielding 10 results). Run tests:

cd lynx-travel-agent/lynx-skill && go test ./gwt/ -v

Differences from lynx-mcp-server

  • Stateless: no background server, no SSE, no Bearer token
  • Attachment upload: reads files from disk directly (not base64)
  • Session: each command authenticates independently (fresh JSESSIONID)
  • Flag style: --kebab-case flags (CLI convention); MCP uses camelCase
  • Binary name: the CLI binary is lynx (vs the MCP server binary lynx-mcp-server)
  • Output: JSON to stdout, errors to stderr
安全使用建议
Install only if you understand that this tool can read and modify live Lynx reservation documents and upload selected local files to Lynx. Avoid enabling LYNX_DEBUG unless you can protect and clean /tmp output, do not paste raw LYNX_* values into logs or support chats, and review upload/save commands carefully before running them against production records.
能力标签
requires-oauth-tokenrequires-sensitive-credentials
能力评估
Purpose & Capability
The skill's search, itinerary retrieval, document save, and attachment upload capabilities match its stated purpose of operating against Lynx Reservations, but they involve sensitive customer travel records and live document mutations.
Instruction Scope
The main commands are documented, including upload and save operations, but the artifacts do not clearly disclose the LYNX_DEBUG behavior that writes raw responses to disk; credential troubleshooting guidance also encourages printing raw LYNX environment values.
Install Mechanism
Installation is a source build/copy workflow with no observed installer script, daemon, auto-start entry, or package-time execution.
Credentials
Use of LYNX_USERNAME, LYNX_PASSWORD, and LYNX_COMPANY_CODE and HTTPS calls to www.lynx-reservations.com are proportionate for this integration, but users should treat the environment and command output as sensitive.
Persistence & Privilege
The CLI is otherwise stateless, but client.go writes raw itinerary and file-document responses to predictable /tmp files with 0644 permissions whenever LYNX_DEBUG is set, creating under-disclosed local persistence of sensitive data.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install lynx-skill
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /lynx-skill 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
lynx-skill v1.0.0 - Initial release of a stateless Go CLI for the Lynx Reservations system. - Provides standalone commands mirroring lynx-mcp-server tools (no server or background processes). - Supports file search, itinerary retrieval, document management, and attachment uploads. - All commands output JSON to stdout and accept credentials via environment variables. - Detailed flag and output documentation included for each command.
元数据
Slug lynx-skill
版本 1.0.0
许可证 MIT-0
累计安装 0
当前安装数 0
历史版本数 1
常见问题

Lynx Skill 是什么?

Stateless Go CLI for the Lynx Reservations (www.lynx-reservations.com) travel agency system. Use this skill whenever the user needs to search files, retrieve... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 33 次。

如何安装 Lynx Skill?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install lynx-skill」即可一键安装,无需额外配置。

Lynx Skill 是免费的吗?

是的,Lynx Skill 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。

Lynx Skill 支持哪些平台?

Lynx Skill 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 Lynx Skill?

由 Fred Ghilini(@fredguile)开发并维护,当前版本 v1.0.0。

💬 留言讨论