This is an automated email from the ASF dual-hosted git repository.

ColinLeeo pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/tsfile.git


The following commit(s) were added to refs/heads/develop by this push:
     new 769aa6d44 feat: add tsfile skills (#907)
769aa6d44 is described below

commit 769aa6d440999489f245223f33b3a26c2dc212ab
Author: Zeyu Zhang <[email protected]>
AuthorDate: Thu Aug 20 18:34:46 2026 +0800

    feat: add tsfile skills (#907)
---
 .gitignore                                |   2 +
 skills/tsfile-cli/SKILL.md                | 120 ++++++++++++
 skills/tsfile/LICENSE                     | 195 ++++++++++++++++++
 skills/tsfile/SKILL.md                    | 103 ++++++++++
 skills/tsfile/assets/TsFileExample.java   |  54 +++++
 skills/tsfile/assets/pom.xml              |  48 +++++
 skills/tsfile/assets/tsfile_example.cpp   | 114 +++++++++++
 skills/tsfile/assets/tsfile_example.py    | 118 +++++++++++
 skills/tsfile/references/c.md             |  48 +++++
 skills/tsfile/references/compatibility.md |  78 ++++++++
 skills/tsfile/references/core-concepts.md |  78 ++++++++
 skills/tsfile/references/cpp.md           |  80 ++++++++
 skills/tsfile/references/docs-map.yaml    | 133 +++++++++++++
 skills/tsfile/references/java.md          |  73 +++++++
 skills/tsfile/references/performance.md   |  63 ++++++
 skills/tsfile/references/python.md        |  85 ++++++++
 skills/tsfile/references/source-policy.md |  95 +++++++++
 skills/tsfile/scripts/build_tsfile.sh     | 218 +++++++++++++++++++++
 skills/tsfile/scripts/example.py          | 315 ++++++++++++++++++++++++++++++
 skills/tsfile/scripts/resolve-version.sh  | 240 +++++++++++++++++++++++
 skills/tsfile/scripts/validate-assets.sh  | 214 ++++++++++++++++++++
 21 files changed, 2474 insertions(+)

diff --git a/.gitignore b/.gitignore
index fcd5f2b6b..ed38cf7c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,8 @@ docs/src/.vuepress/dist/
 docs/pnpm-lock.yaml
 
 # python files
+skills/**/__pycache__/
+skills/**/*.py[cod]
 python/build
 python/dist
 python/__pycache__
diff --git a/skills/tsfile-cli/SKILL.md b/skills/tsfile-cli/SKILL.md
new file mode 100644
index 000000000..37c59a207
--- /dev/null
+++ b/skills/tsfile-cli/SKILL.md
@@ -0,0 +1,120 @@
+---
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+name: tsfile-cli
+description: Use when you need to inspect, preview, export, OR import an 
Apache TsFile (.tsfile) from the command line — list devices/tables, dump 
schema, read file/series metadata, count rows, sample/preview rows, or write 
CSV/TSV into a new .tsfile — via the project's C++ `tsfile-cli` in cpp/tools.
+---
+
+# tsfile-cli
+
+Single pipe-friendly C++ binary to inspect **and** import `.tsfile` (TsFile's 
analogue of
+`parquet-cli`/`pqrs`). Source `cpp/tools/`. Read data → stdout, diagnostics → 
stderr;
+`write` imports CSV/TSV → a new file.
+
+## Scope
+
+Use this skill for command-line builds and operations. For Java, Python, C++,
+or C SDK integration, schema design, and programmatic tree-model writes, load
+the sibling `tsfile` skill at `../tsfile/SKILL.md`.
+
+## Binary
+
+- Name `tsfile-cli` (CMake target `tsfile_cli`). Find: `ls 
cpp/build/*/bin/tsfile-cli`.
+- Build only if missing: `cd cpp && bash build.sh -t=Debug`.
+
+## Read
+
+`tsfile-cli <cmd> [opts] <file.tsfile>` · `tsfile-cli --help | --version | 
help`
+
+| cmd | output | scans pages |
+|---|---|---|
+| `ls` | device (tree) / table (table) per line | no |
+| `schema` | `target,measurement,datatype,encoding,compression` | no |
+| `meta` | model, device/table/series counts, time range, size | no |
+| `stats` | per-series `count,start,end,min,max,first,last,sum` | no |
+| `count` | per-series counts + `total` row | no |
+| `head` | first N rows (default 10, `-n`) | yes |
+| `cat` | all matching rows (streamed; `table` format buffers) | yes |
+| `sample` | reservoir sample (default 10, `-n` + `--seed`) | yes |
+
+Prefer no-scan verbs (`ls/schema/meta/stats/count`) — cheap and never hit the 
page-decode caveat.
+
+Table model + row verbs (`head/cat/sample`): without `-t`, only the **first** 
table is queried. Pass `-t <table>` to target a specific one (`count` covers 
all tables).
+
+```
+opts: -f csv|tsv|json|table  (default TTY→table, pipe→tsv)
+      -d <device> | -t <table>   (mutually exclusive)
+      -m a,b,c (projection) · -n N · --offset N · --start <ms> · --end <ms> 
(inclusive)
+      --tag-filter C OP V · --tag-between C L U · --tag-not-between C L U 
(table TAG predicates)
+      --seed N · --no-header · --model tree|table (else auto)
+applies: -m → schema/stats/count/head/cat/sample · -d/-t → row 
cmds/schema/stats/count
+         (-d needs tree model, -t needs table model in head/cat/sample/schema) 
· --offset ∉ sample
+         tag filters → head/cat/sample table model; 
OP=eq|neq|lt|lteq|gt|gteq|regexp|not-regexp
+json=NDJSON (num/bool bare, else quoted, null→null, NaN/Inf→null) · 
csv=RFC4180 · ts=raw epoch ms
+exit: 0 ok · 1 usage · 2 file open/corrupt · 3 query/runtime
+```
+
+The aligned `table` format buffers rows. Prefer `csv`, `tsv`, or `json` for
+large dumps and pipelines.
+
+```sh
+B=cpp/build/Debug/bin/tsfile-cli
+$B meta data.tsfile; $B count -t table1 -f tsv data.tsfile
+$B cat -t table1 --tag-filter device eq dev_1 -m temp -f tsv data.tsfile
+$B cat -m temp --start 1700000000000 -f csv data.tsfile 2>/dev/null | head
+```
+
+## Write
+
+`tsfile-cli write --table <name> --columns <spec> -o <out> [-f csv|tsv] 
[--no-header] [--header-match] [-v] [<input> | -]`
+
+Imports rows into a **new table-model** file (overwritten). Input col 0 = 
timestamp
+(epoch ms, int); remaining cols declared by `--columns` — **no type 
inference**.
+
+```
+spec  := col (',' col)*
+col   := name ':' TYPE ':' ('tag' | 'field')          # TYPE + category 
case-insensitive
+TYPE  ∈ { BOOLEAN, INT32, INT64, FLOAT, DOUBLE, STRING, TEXT, TIMESTAMP, DATE, 
BLOB }
+input := file | '-' | omitted                          # '-' or omitted = stdin
+```
+
+- `-o` required (overwritten, must differ from input); `-f` default csv 
(json/table → usage error).
+- header: first line skipped by default · `--no-header` if none · 
`--header-match` validates
+  header names vs `--columns` (mutually exclusive with `--no-header`).
+- empty cell = null · `--table` is lower-cased · `DATE` cells are 
`YYYY-MM-DD`, `TIMESTAMP` epoch ms · each column stored with the engine default 
encoding/compression for its type · success **silent**, `-v` → echoes the 
resolved config + `wrote N rows to <out>` on stderr.
+- **timestamps must be strictly increasing per device** (device = tag-column 
values); rows for
+  different tags may interleave/reuse timestamps. Out-of-order input → error 
with line number.
+- a failed import deletes its partial output (no half-written `.tsfile` left 
behind).
+- exit: `1` usage (missing `--table`/`--columns`/`-o`, bad spec, dup column, 
read-only flag) · `2` IO open · `3` row (field-count / type / overflow / 
timestamp-order / header mismatch).
+
+```sh
+printf 'time,id1,s1\n0,dev,0\n1,dev,10\n' \
+  | tsfile-cli write --table t1 --columns "id1:STRING:tag,s1:INT64:field" -o 
out.tsfile -
+tsfile-cli count -f tsv out.tsfile        # -> t1.dev  s1  2
+```
+
+Tree-model / JSON / programmatic writes → C++ SDK 
`cpp/examples/cpp_examples/demo_write.cpp`
+(`TsFileTableWriter`/`TsFileWriter` + `Tablet`); Java/Python writers under 
`java/`, `python/`.
+
+## Caveats
+
+- `head`/`cat`/`sample` decode pages → may abort (`decode_cur_time_page_data`, 
exit 134) on
+  some aligned files incl. bundled `cpp/examples/test_cpp.tsfile`. 
Storage-engine/file issue,
+  not a CLI bug; metadata verbs still work. Use a well-formed (e.g. 
self-written) file for rows.
+- table-model `target` is derived from tag bytes → may show non-printable 
chars in `stats/count/schema`.
+- `schema` lists all columns; `meta/stats/count` count only field series → 
`series_count` can be
+  fewer than `schema` rows (not a bug).
diff --git a/skills/tsfile/LICENSE b/skills/tsfile/LICENSE
new file mode 100644
index 000000000..6d3e376bd
--- /dev/null
+++ b/skills/tsfile/LICENSE
@@ -0,0 +1,195 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (which shall not include Derivative Works that are defined below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based upon (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and derivative works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control
+      systems, and issue tracking systems that are managed by, or on behalf
+      of, the Licensor for the purpose of discussing and improving the Work,
+      but excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to use, reproduce, modify, display, perform,
+      sublicense, and distribute the Work and such Derivative Works in
+      Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, trademark, patent,
+          attribution and other notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright notice and license terms for Your use,
+      reproduction, and distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Support. You may choose to offer, and to
+      charge a fee for, warranty, support, indemnity or other liability
+      obligations and/or rights consistent with this License. However, in
+      accepting such obligations, You may act only on Your own behalf and on
+      Your sole responsibility, not on behalf of any other Contributor, and
+      only if You agree to indemnify, defend, and hold each Contributor
+      harmless for any liability incurred by, or claims asserted against,
+      such Contributor by reason of your accepting any such warranty or 
support.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in appropriate
+      comment syntax for the file format. We use "/* ... */" format
+      here, but adapt as needed.
+
+      Copyright [yyyy] [name of copyright owner]
+
+      Licensed under the Apache License, Version 2.0 (the "License");
+      you may not use this file except in compliance with the License.
+      You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+      Unless required by applicable law or agreed to in writing, software
+      distributed under the License is distributed on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      See the License for the specific language governing permissions and
+      limitations under the License.
\ No newline at end of file
diff --git a/skills/tsfile/SKILL.md b/skills/tsfile/SKILL.md
new file mode 100644
index 000000000..360b8df26
--- /dev/null
+++ b/skills/tsfile/SKILL.md
@@ -0,0 +1,103 @@
+---
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+name: tsfile
+description: Work with Apache TsFile programmatic SDKs and file-format 
concepts in Java, Python, C++, or C. Use for reading, writing, querying, schema 
or data-model design, encoding/compression decisions, performance analysis, API 
compatibility, and cross-language TsFile integration. Route shell inspection, 
preview, export, sampling, and CSV/TSV conversion to the sibling tsfile-cli 
skill.
+---
+
+# TsFile
+
+## Scope
+
+Use this skill for SDK code, Tree/Table model decisions, schema design,
+compatibility, and cross-language integration. Use the sibling
+`../tsfile-cli/SKILL.md` for shell-oriented inspection, preview, export,
+sampling, and CSV/TSV-to-TsFile conversion.
+
+## Operating Rules
+
+1. Before giving a dependency version or version-sensitive API, run
+   `scripts/resolve-version.sh`. Pass `--root <checkout>` when the target is 
not
+   the repository that bundles this skill. When no checkout is present, the
+   script returns the current skill baseline. Inspect external dependency
+   metadata only when the user targets a different project or release. Do not
+   treat `latest` as a release number. Read `references/source-policy.md` only
+   when the authority remains ambiguous, sources conflict, or a
+   freshness/published-release claim matters.
+2. Use `references/docs-map.yaml` only when an official online page, release,
+   download, or repository link is needed.
+3. Choose Tree or Table model, then choose one language binding. Do not load 
all
+   language references by default.
+4. Close writers, readers, and result sets so file footers and native resources
+   are finalized. Validate files with every language that must consume them.
+
+## Offline Reference Routing
+
+Read only the files required by the current task:
+
+- Source authority, version conflicts, offline/online selection, and update
+  rules: `references/source-policy.md`
+- Official website, download, release, and repository URL registry:
+  `references/docs-map.yaml`
+- Model selection, schema, data types, and generic read/write workflow:
+  `references/core-concepts.md`
+- Java SDK code and API guardrails: `references/java.md`
+- Python SDK code and binding-specific behavior: `references/python.md`
+- C++ SDK code and resource management: `references/cpp.md`
+- C wrapper entry points and lifecycle: `references/c.md`
+- Version resolution, build requirements, and cross-version checks:
+  `references/compatibility.md`
+- Encoding, compression, throughput, memory, or storage tuning:
+  `references/performance.md`
+
+Do not read `references/performance.md` for ordinary API questions. Do not read
+multiple language references unless the task explicitly crosses languages.
+
+## Workflow
+
+For writes, select the model and schema, prefer tablet/batch APIs, write data,
+flush where required, close the writer, and reopen the result for validation.
+
+For reads, identify the model and schema, select only needed columns, bound the
+time range when possible, consume the result incrementally, and close all
+resources.
+
+For compatibility questions, report the local source version and the requested
+release separately. Never silently combine signatures from different versions
+or language bindings.
+
+## Bundled Resources
+
+- Run `scripts/resolve-version.sh [--root <checkout>]` to obtain Maven, C++,
+  Python, and Git version metadata without loading or copying source files. Its
+  output schema remains stable when no checkout is discovered and then reports
+  the baseline shipped with this skill.
+- When a compatible checkout is available, use maintained examples from the
+  same commit: `java/examples/`, `python/examples/example.py`, or
+  `cpp/examples/`. Do not copy an `assets/` template merely to answer an API
+  question.
+- When no compatible checkout is available and the user requests a starter
+  project, copy only the needed files from `assets/`. Supply the target Java
+  dependency as `-Dtsfile.version=<version>`; the template intentionally
+  contains no default TsFile version.
+- Run `scripts/validate-assets.sh [--root <checkout>]` after changing a
+  template. It automatically uses a compatible checkout when found and always
+  performs dependency-free checks. Explicitly select an external dependency
+  with either `--tsfile-version <version>` or `--java-jar <path>` for Java,
+  `--cpp-include <dir>` for C++, or `--python-runtime` for Python.
+- Use `scripts/build_tsfile.sh` for repository language build checks.
+- Use `scripts/example.py` only for Python API metadata or writer examples.
diff --git a/skills/tsfile/assets/TsFileExample.java 
b/skills/tsfile/assets/TsFileExample.java
new file mode 100644
index 000000000..b5907fd9d
--- /dev/null
+++ b/skills/tsfile/assets/TsFileExample.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.write.record.TSRecord;
+import org.apache.tsfile.write.schema.MeasurementSchema;
+import org.apache.tsfile.write.v4.TsFileTreeWriter;
+import org.apache.tsfile.write.v4.TsFileTreeWriterBuilder;
+
+import java.io.File;
+import java.nio.file.Files;
+
+public class TsFileExample {
+  public static void main(String[] args) throws Exception {
+    File file = new File("example.tsfile");
+    Files.deleteIfExists(file.toPath());
+
+    String deviceId = "sensor_01";
+    try (TsFileTreeWriter writer = new 
TsFileTreeWriterBuilder().file(file).build()) {
+      writer.registerTimeseries(
+          deviceId, new MeasurementSchema("temperature", TSDataType.FLOAT));
+      writer.registerTimeseries(deviceId, new MeasurementSchema("humidity", 
TSDataType.FLOAT));
+      writer.registerTimeseries(deviceId, new MeasurementSchema("pressure", 
TSDataType.DOUBLE));
+
+      for (int i = 0; i < 100; i++) {
+        long timestamp = System.currentTimeMillis() + i * 1000L;
+        TSRecord record =
+            new TSRecord(deviceId, timestamp)
+                .addPoint("temperature", 20.0f + i * 0.1f)
+                .addPoint("humidity", 50.0f + i * 0.5f)
+                .addPoint("pressure", 1013.25 + i * 0.01);
+        writer.write(record);
+      }
+    }
+
+    System.out.println("TsFile written successfully: " + 
file.getAbsolutePath());
+  }
+}
diff --git a/skills/tsfile/assets/pom.xml b/skills/tsfile/assets/pom.xml
new file mode 100644
index 000000000..837814433
--- /dev/null
+++ b/skills/tsfile/assets/pom.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.example</groupId>
+    <artifactId>tsfile-example</artifactId>
+    <version>1.0.0</version>
+    <properties>
+        <maven.compiler.release>17</maven.compiler.release>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <!-- Run Maven with -Dtsfile.version=<the target project's TsFile 
version>. -->
+        <dependency>
+            <groupId>org.apache.tsfile</groupId>
+            <artifactId>tsfile</artifactId>
+            <version>${tsfile.version}</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <!-- Keep TsFileExample.java beside this POM in the copied template. 
-->
+        <sourceDirectory>${project.basedir}</sourceDirectory>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.13.0</version>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/skills/tsfile/assets/tsfile_example.cpp 
b/skills/tsfile/assets/tsfile_example.cpp
new file mode 100644
index 000000000..8fa15d4c3
--- /dev/null
+++ b/skills/tsfile/assets/tsfile_example.cpp
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <fcntl.h>
+#include <file/write_file.h>
+#include <reader/tsfile_reader.h>
+#include <writer/tsfile_table_writer.h>
+
+#include <cstdint>
+#include <cstdio>
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace {
+
+int check(int code, const char* operation) {
+    if (code != common::E_OK) {
+        std::cerr << operation << " failed with error " << code << std::endl;
+    }
+    return code;
+}
+
+}  // namespace
+
+int main() {
+    storage::libtsfile_init();
+
+    const std::string file_name = "example_cpp.tsfile";
+    const std::string table_name = "sensors";
+    std::remove(file_name.c_str());
+
+    {
+        storage::WriteFile file;
+        int flags = O_WRONLY | O_CREAT | O_TRUNC;
+#ifdef _WIN32
+        flags |= O_BINARY;
+#endif
+        if (check(file.create(file_name, flags, 0666), "open writer") !=
+            common::E_OK) {
+            return 1;
+        }
+
+        storage::TableSchema schema(
+            table_name,
+            {common::ColumnSchema("device", common::STRING,
+                                  common::UNCOMPRESSED, common::PLAIN,
+                                  common::ColumnCategory::TAG),
+             common::ColumnSchema("temperature", common::DOUBLE,
+                                  common::UNCOMPRESSED, common::PLAIN,
+                                  common::ColumnCategory::FIELD)});
+        storage::TsFileTableWriter writer(&file, &schema);
+        storage::Tablet tablet(
+            table_name, {"device", "temperature"},
+            {common::STRING, common::DOUBLE},
+            {common::ColumnCategory::TAG, common::ColumnCategory::FIELD}, 5);
+
+        for (uint32_t row = 0; row < 5; ++row) {
+            tablet.add_timestamp(row, row);
+            tablet.add_value(row, "device", "sensor_01");
+            tablet.add_value(row, "temperature", 20.0 + row * 0.5);
+        }
+
+        if (check(writer.write_table(tablet), "write table") != common::E_OK ||
+            check(writer.flush(), "flush writer") != common::E_OK ||
+            check(writer.close(), "close writer") != common::E_OK) {
+            return 1;
+        }
+    }
+
+    {
+        storage::TsFileReader reader;
+        if (check(reader.open(file_name), "open reader") != common::E_OK) {
+            return 1;
+        }
+
+        storage::ResultSet* result = nullptr;
+        std::vector<std::string> columns{"device", "temperature"};
+        if (check(reader.query(table_name, columns, 0, 4, result), "query") !=
+            common::E_OK) {
+            return 1;
+        }
+
+        bool has_next = false;
+        int code = common::E_OK;
+        while ((code = result->next(has_next)) == common::E_OK && has_next) {
+            std::cout << result->get_value<double>("temperature") << std::endl;
+        }
+        result->close();
+        reader.close();
+        if (check(code, "read row") != common::E_OK) {
+            return 1;
+        }
+    }
+
+    storage::libtsfile_destroy();
+    return 0;
+}
diff --git a/skills/tsfile/assets/tsfile_example.py 
b/skills/tsfile/assets/tsfile_example.py
new file mode 100755
index 000000000..6982bb47f
--- /dev/null
+++ b/skills/tsfile/assets/tsfile_example.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python3
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Current table-model write/read example for the TsFile Python binding."""
+
+import os
+import sys
+from datetime import datetime, timedelta
+
+import pandas as pd
+
+try:
+    from tsfile import (
+        ColumnCategory,
+        ColumnSchema,
+        TableSchema,
+        Tablet,
+        TSDataType,
+        TsFileReader,
+        TsFileTableWriter,
+    )
+except ImportError:
+    print("TsFile Python library not found.")
+    print("Build it from the repository root with: ./mvnw -P with-python clean 
verify")
+    sys.exit(1)
+
+
+def generate_sample_data(num_devices=2, records_per_device=10):
+    rows = []
+    base_time = datetime.now()
+    for device_id in range(1, num_devices + 1):
+        for offset in range(records_per_device):
+            rows.append(
+                {
+                    "timestamp": base_time + timedelta(seconds=offset * 10),
+                    "device": f"sensor_{device_id:02d}",
+                    "temperature": 20.0 + device_id + offset * 0.5,
+                    "online": offset % 5 != 0,
+                }
+            )
+    return pd.DataFrame(rows)
+
+
+def normalize_schemas(schemas):
+    if isinstance(schemas, dict):
+        return schemas
+    return {schema.get_table_name(): schema for schema in schemas or []}
+
+
+def write_example(file_name):
+    columns = [
+        ColumnSchema("device", TSDataType.STRING, ColumnCategory.TAG),
+        ColumnSchema("temperature", TSDataType.DOUBLE, ColumnCategory.FIELD),
+        ColumnSchema("online", TSDataType.BOOLEAN, ColumnCategory.FIELD),
+    ]
+    schema = TableSchema("sensors", columns)
+    frame = generate_sample_data()
+
+    with TsFileTableWriter(file_name, schema) as writer:
+        batch_size = 10
+        for start in range(0, len(frame), batch_size):
+            batch = frame.iloc[start : start + batch_size]
+            tablet = Tablet(
+                schema.get_column_names(),
+                [column.get_data_type() for column in schema.get_columns()],
+                len(batch),
+            )
+            for row_index, (_, row) in enumerate(batch.iterrows()):
+                timestamp_ms = int(row["timestamp"].timestamp() * 1000)
+                tablet.add_timestamp(row_index, timestamp_ms)
+                tablet.add_value_by_name("device", row_index, 
str(row["device"]))
+                tablet.add_value_by_name(
+                    "temperature", row_index, float(row["temperature"])
+                )
+                tablet.add_value_by_name("online", row_index, 
bool(row["online"]))
+            writer.write_table(tablet)
+
+
+def read_example(file_name):
+    with TsFileReader(file_name) as reader:
+        schemas = normalize_schemas(reader.get_all_table_schemas())
+        for table_name, schema in schemas.items():
+            columns = [
+                column.get_column_name()
+                for column in schema.get_columns()
+                if column.get_category() != ColumnCategory.TIME
+            ]
+            with reader.query_table_by_row(table_name, columns, limit=5) as 
result:
+                print(result.read_data_frame(max_row_num=5))
+
+
+def main():
+    file_name = "example_python.tsfile"
+    if os.path.exists(file_name):
+        os.remove(file_name)
+    write_example(file_name)
+    read_example(file_name)
+    print(f"Generated {file_name}")
+    return 0
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/skills/tsfile/references/c.md b/skills/tsfile/references/c.md
new file mode 100644
index 000000000..843de32c6
--- /dev/null
+++ b/skills/tsfile/references/c.md
@@ -0,0 +1,48 @@
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+# C Wrapper
+
+Use this reference only for the C wrapper around the C++ implementation. Read
+`cpp/src/cwrapper/tsfile_cwrapper.h` before generating exact signatures.
+
+## Maintained Examples
+
+- Write: `cpp/examples/c_examples/demo_write.c`
+- Read: `cpp/examples/c_examples/demo_read.c`
+
+## Current API Families
+
+- File/writer creation: `write_file_new`, `tsfile_writer_new`.
+- Tablet creation and population: `tablet_new`, `tablet_add_timestamp`, and
+  typed `tablet_add_value_by_name_*` functions.
+- Write: `tsfile_writer_write`.
+- Reader/query: `tsfile_reader_new`, `tsfile_query_table`.
+- Cleanup: use the matching close and `free_*` functions demonstrated by the
+  maintained examples.
+
+## Guardrails
+
+- Do not invent opaque wrapper names or infer signatures from C++ methods.
+- Pair every allocation with the matching cleanup call, including error paths.
+- Preserve ownership long enough for writer/tablet operations that retain
+  pointers.
+- Verify the wrapper and linked C++ library come from compatible builds.
+- Compile and run the maintained C examples before adapting them into another
+  build system.
diff --git a/skills/tsfile/references/compatibility.md 
b/skills/tsfile/references/compatibility.md
new file mode 100644
index 000000000..d261548fa
--- /dev/null
+++ b/skills/tsfile/references/compatibility.md
@@ -0,0 +1,78 @@
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+# Version and Compatibility
+
+Use this offline reference before selecting an API signature or diagnosing a
+build/runtime mismatch.
+
+## Resolve the Target
+
+- Run `scripts/resolve-version.sh` for the checkout that bundles the skill, or
+  `scripts/resolve-version.sh --root <checkout>` for another TsFile source 
tree.
+- If no checkout is present, `version_source=skill_baseline` identifies the
+  current TsFile source baseline shipped with this skill.
+- Use its Maven/Java, C++, Python, and Git fields independently; do not assume
+  every language package uses an identical version string.
+- External project: inspect Maven, Python, CMake, package-manager, lockfile, or
+  deployed artifact metadata only when it intentionally targets a different
+  TsFile release.
+
+The offline API references target the current source baseline. Update the
+baseline metadata and re-audit affected references before publishing them with
+a newer TsFile source version.
+
+## Build Baseline for This Source Line
+
+- Java: JDK 17 and Maven 3.6+; prefer the repository `./mvnw`.
+- C++: CMake 3.11+, a C++11 compiler, make, clang-format, and platform UUID
+  headers where required. Optional bundled LZMA2 requires CMake 3.20+; on CMake
+  3.11 through 3.19, use a compatible system liblzma or leave LZMA2 disabled.
+- Python: Python 3.9+ and the C++ module built by the `with-python` profile.
+
+Repository checks:
+
+```bash
+./mvnw -P with-java clean verify
+./mvnw -P with-cpp clean verify
+./mvnw -P with-python clean verify
+```
+
+## Compatibility Guardrails
+
+1. Prefer examples, tests, and public headers from the same commit.
+2. Keep Java, Python, C++, and C signatures separate; similarly named methods
+   may have different arguments, ownership, or return types.
+3. Do not copy a snapshot version into an external project unless the artifact
+   from this baseline is installed or deployed where that project resolves
+   dependencies.
+4. Treat published `latest` documentation and the current source checkout as
+   separate authorities when their versions differ.
+5. Validate cross-language files using every required reader and representative
+   null, time, text, date, and binary values.
+6. Close writers, readers, and result sets to finalize file structures and
+   release native resources.
+
+## Troubleshooting Order
+
+1. Confirm the library and file versions.
+2. Reproduce with a maintained example from the same checkout.
+3. Confirm the selected Tree/Table model and schema.
+4. Check resource closure and native-library availability.
+5. Reduce to a minimal file before attributing the failure to corruption.
diff --git a/skills/tsfile/references/core-concepts.md 
b/skills/tsfile/references/core-concepts.md
new file mode 100644
index 000000000..4cebe21e9
--- /dev/null
+++ b/skills/tsfile/references/core-concepts.md
@@ -0,0 +1,78 @@
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+# TsFile Core Concepts
+
+Use this offline reference for model selection, schema design, supported value
+types, and the language-independent read/write lifecycle. Read a language
+reference separately only after selecting the binding.
+
+## Data Models
+
+- Tree model identifies a time series by device and measurement. Use it when
+  device paths and measurement hierarchies are the natural identity.
+- Table model organizes data into tables. TAG columns identify a device or
+  entity; FIELD columns store measured values.
+- Do not translate Tree and Table APIs by name alone. Their registration,
+  filtering, and result APIs differ.
+
+## Schema Decisions
+
+- Use TAG columns for identifiers and relatively static dimensions such as
+  device, location, or sensor type.
+- Use FIELD columns for observations such as temperature, pressure, status, or
+  counters.
+- Choose the narrowest type that preserves the input domain:
+  - `BOOLEAN` for flags.
+  - `INT32` or `INT64` for integral values and counters.
+  - `FLOAT` or `DOUBLE` for measurements requiring fractional precision.
+  - `STRING` or `TEXT` for textual values; availability and naming may differ
+    by binding.
+  - `TIMESTAMP` and `DATE` for time-valued fields.
+  - `BLOB` for opaque binary data.
+- Confirm that the chosen binding supports a type/encoding combination before
+  overriding defaults.
+
+## Write Lifecycle
+
+1. Select Tree or Table model.
+2. Define and register the schema required by that model.
+3. Create a writer.
+4. Populate tablets/batches for normal throughput; use single-record writes
+   only when latency or application structure requires them.
+5. Write complete batches, flush when required by the binding, and close the
+   writer to finalize the file.
+6. Reopen the file and validate schema plus representative values.
+
+## Read Lifecycle
+
+1. Open the file with the matching reader.
+2. Discover or provide the model and schema.
+3. Select only required measurements or columns.
+4. Bound the time range and supported filters when possible.
+5. Consume rows or columnar batches incrementally.
+6. Close the result set before closing the reader.
+
+## Cross-Language Files
+
+- Write with one binding and read with every binding required by the target
+  system.
+- Verify nulls, timestamps, textual values, `DATE`, and `BLOB` explicitly;
+  language representations may differ even when the file type is compatible.
+- Keep the writer and readers on compatible TsFile format/library versions.
diff --git a/skills/tsfile/references/cpp.md b/skills/tsfile/references/cpp.md
new file mode 100644
index 000000000..28756373e
--- /dev/null
+++ b/skills/tsfile/references/cpp.md
@@ -0,0 +1,80 @@
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+# C++ SDK
+
+Use this reference only for C++ SDK work. Verify exact constructors and
+ownership against public headers under `cpp/src/` in the target checkout.
+
+## Table-Model Write
+
+```cpp
+storage::WriteFile file;
+file.create("data.tsfile", O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+storage::TableSchema schema(
+    "sensors",
+    {common::ColumnSchema("device", common::STRING, common::UNCOMPRESSED,
+                          common::PLAIN, common::ColumnCategory::TAG),
+     common::ColumnSchema("temperature", common::DOUBLE, common::UNCOMPRESSED,
+                          common::PLAIN, common::ColumnCategory::FIELD)});
+
+storage::TsFileTableWriter writer(&file, &schema);
+storage::Tablet tablet(
+    "sensors", {"device", "temperature"},
+    {common::STRING, common::DOUBLE},
+    {common::ColumnCategory::TAG, common::ColumnCategory::FIELD}, 1);
+tablet.add_timestamp(0, 1);
+tablet.add_value(0, "device", "d1");
+tablet.add_value(0, "temperature", 20.5);
+writer.write_table(tablet);
+writer.flush();
+writer.close();
+```
+
+The current method is `write_table(Tablet&)`, not `write_tablet`. Flush
+buffered rows before closing as demonstrated by the maintained examples.
+
+## Table-Model Read
+
+```cpp
+storage::TsFileReader reader;
+reader.open("data.tsfile");
+
+storage::ResultSet* result = nullptr;
+std::vector<std::string> columns{"device", "temperature"};
+reader.query("sensors", columns, 0, 100, result);
+
+bool has_next = false;
+while (result->next(has_next) == common::E_OK && has_next) {
+  double temperature = result->get_value<double>("temperature");
+}
+result->close();
+reader.close();
+```
+
+## Guidance
+
+- Current readers use `query(..., ResultSet*&)`; do not reuse old
+  `get_table_names()` or `read_table()` helpers without version verification.
+- Prefer stack/RAII ownership where supported, but still follow explicit
+  close/free requirements in the public API and examples.
+- Use `cpp/examples/cpp_examples/` as executable API documentation.
+- Verify with `./mvnw -P with-cpp clean verify` or the checkout's documented
+  `cpp/build.sh` flow.
diff --git a/skills/tsfile/references/docs-map.yaml 
b/skills/tsfile/references/docs-map.yaml
new file mode 100644
index 000000000..4fb4f342f
--- /dev/null
+++ b/skills/tsfile/references/docs-map.yaml
@@ -0,0 +1,133 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+schema_version: 1
+last_verified: "2026-08-17"
+policy_reference: references/source-policy.md
+path_bases:
+  policy_reference: skill_root
+  local_fallbacks_and_authorities: tsfile_repository_root
+
+skill_baseline:
+  scope: current-source
+  source_ref: develop
+  maven_project_version: "2.3.2-SNAPSHOT"
+  java_release: "17"
+  cpp_sdk_version: "2.3.2.dev"
+  python_package_version: "2.3.2.dev"
+
+official_url_prefixes:
+  - https://tsfile.apache.org/
+  - https://github.com/apache/tsfile
+
+release_sources:
+  - id: apache-downloads-zh
+    purpose: published_artifacts
+    url: https://tsfile.apache.org/zh/Download/
+    mutable: true
+  - id: github-releases
+    purpose: release_notes_and_tags
+    url: https://github.com/apache/tsfile/releases
+    mutable: true
+  - id: source-develop
+    purpose: active_development_source
+    url: https://github.com/apache/tsfile/tree/develop
+    version_scope: develop
+    mutable: true
+
+guide_roots:
+  - id: user-guide-v2-zh
+    locale: zh-CN
+    version_scope: v2.x_latest_alias
+    url: https://tsfile.apache.org/zh/UserGuide/latest/
+    mutable: true
+  - id: user-guide-v2-en
+    locale: en
+    version_scope: v2.x_latest_alias
+    url: https://tsfile.apache.org/UserGuide/latest/
+    mutable: true
+concepts:
+  - id: time-series-concepts-zh
+    url: 
https://tsfile.apache.org/zh/UserGuide/latest/QuickStart/Navigating_Time_Series_Data.html
+    version_scope: v2.x_latest_alias
+    local_fallbacks:
+      - docs/src/zh/UserGuide/latest/QuickStart/Navigating_Time_Series_Data.md
+      - skills/tsfile/references/core-concepts.md
+  - id: data-model-zh
+    url: 
https://tsfile.apache.org/zh/UserGuide/latest/QuickStart/Data-Model.html
+    version_scope: v2.x_latest_alias
+    local_fallbacks:
+      - docs/src/zh/UserGuide/latest/QuickStart/Data-Model.md
+      - skills/tsfile/references/core-concepts.md
+
+language_guides:
+  java:
+    quick_start: 
https://tsfile.apache.org/zh/UserGuide/latest/QuickStart/QuickStart.html
+    interface: 
https://tsfile.apache.org/zh/UserGuide/latest/QuickStart/InterfaceDefinition/InterfaceDefinition-Java.html
+    version_scope: v2.x_latest_alias
+    local_authorities:
+      - java/examples/src/main/java/org/apache/tsfile/v4/
+      - java/tsfile/src/main/java/
+      - skills/tsfile/references/java.md
+  python:
+    quick_start: 
https://tsfile.apache.org/zh/UserGuide/latest/QuickStart/QuickStart-PYTHON.html
+    interface: 
https://tsfile.apache.org/zh/UserGuide/latest/QuickStart/InterfaceDefinition/InterfaceDefinition-Python.html
+    version_scope: v2.x_latest_alias
+    local_authorities:
+      - python/examples/example.py
+      - python/tsfile/
+      - python/tests/
+      - skills/tsfile/references/python.md
+  cpp:
+    quick_start: 
https://tsfile.apache.org/zh/UserGuide/latest/QuickStart/QuickStart-CPP.html
+    interface: 
https://tsfile.apache.org/zh/UserGuide/latest/QuickStart/InterfaceDefinition/InterfaceDefinition-CPP.html
+    version_scope: v2.x_latest_alias
+    local_authorities:
+      - cpp/examples/cpp_examples/
+      - cpp/src/
+      - skills/tsfile/references/cpp.md
+  c:
+    quick_start: 
https://tsfile.apache.org/zh/UserGuide/latest/QuickStart/QuickStart-C.html
+    interface: 
https://tsfile.apache.org/zh/UserGuide/latest/QuickStart/InterfaceDefinition/InterfaceDefinition-C.html
+    version_scope: v2.x_latest_alias
+    local_authorities:
+      - cpp/examples/c_examples/
+      - cpp/src/cwrapper/tsfile_cwrapper.h
+      - skills/tsfile/references/c.md
+
+dataframe:
+  guide_zh: 
https://tsfile.apache.org/zh/UserGuide/latest/DataFrame/TsFileDataFrame.html
+  version_scope: v2.x_latest_alias
+  local_authorities:
+    - python/tsfile/
+    - python/tests/
+
+ecosystem:
+  version_policy: verify_connector_dependencies_before_use
+  flink: 
https://tsfile.apache.org/UserGuide/latest/Ecosystem-Integration/Flink-TsFile.html
+  hive: 
https://tsfile.apache.org/UserGuide/latest/Ecosystem-Integration/Hive-TsFile.html
+  spark: 
https://tsfile.apache.org/UserGuide/latest/Ecosystem-Integration/Spark-TsFile.html
+
+tools:
+  owner_skill:
+    path: ../tsfile-cli/SKILL.md
+    base: skill_root
+  cli: https://tsfile.apache.org/UserGuide/latest/Tools/Tsfile-CLI.html
+  viewer: https://tsfile.apache.org/UserGuide/latest/Tools/Tsfile-Viewer.html
+  local_authorities:
+    - cpp/tools/README.md
+    - cpp/tools/
diff --git a/skills/tsfile/references/java.md b/skills/tsfile/references/java.md
new file mode 100644
index 000000000..dfd10930c
--- /dev/null
+++ b/skills/tsfile/references/java.md
@@ -0,0 +1,73 @@
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+# Java SDK
+
+Use this reference only for Java SDK work. Resolve the dependency version from
+the target project or current checkout before using an API.
+
+## Tree-Model Write
+
+```java
+try (TsFileTreeWriter writer =
+    new TsFileTreeWriterBuilder().file(new File("data.tsfile")).build()) {
+  writer.registerTimeseries(
+      "device1", new MeasurementSchema("temperature", TSDataType.FLOAT));
+  TSRecord record =
+      new TSRecord("device1", 1L).addPoint("temperature", 20.5f);
+  writer.write(record);
+}
+```
+
+For the current v4 API, the constructor order is
+`TSRecord(deviceId, timestamp)` and the tree writer method is `write`. Avoid
+deprecated `TsFileWriter.registerTimeseries(Path, ...)` examples from older
+source lines.
+
+## Tree-Model Read
+
+```java
+try (ITsFileTreeReader reader =
+        new TsFileTreeReaderBuilder().file(new File("data.tsfile")).build();
+    ResultSet rows =
+        reader.query(
+            List.of("device1"),
+            List.of("temperature"),
+            Long.MIN_VALUE,
+            Long.MAX_VALUE)) {
+  while (rows.next()) {
+    Float value =
+        rows.isNull("device1.temperature")
+            ? null
+            : rows.getFloat("device1.temperature");
+  }
+}
+```
+
+## Guidance
+
+- Prefer `Tablet` for batch writes and `TSRecord` for genuinely record-oriented
+  flows.
+- Use try-with-resources for writers, readers, and result sets.
+- For work inside the source checkout, use `java/examples/` as executable API
+  documentation and verify with `./mvnw -P with-java clean verify`.
+- For external projects, use an available release instead of assuming the
+  checkout snapshot is publicly deployed.
+- Confirm Tree versus Table examples before adapting a class with a similar
+  name.
diff --git a/skills/tsfile/references/performance.md 
b/skills/tsfile/references/performance.md
new file mode 100644
index 000000000..6972f0aad
--- /dev/null
+++ b/skills/tsfile/references/performance.md
@@ -0,0 +1,63 @@
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+# TsFile Performance and Storage
+
+Load this reference only for throughput, latency, memory, compression, 
encoding,
+or file-size work. Treat every recommendation as a benchmark hypothesis rather
+than a universal setting.
+
+## Write Path
+
+- Prefer tablets/batches over individual records for throughput-oriented
+  ingestion.
+- Benchmark batch size against row width, memory budget, flush frequency, and
+  latency requirements. Avoid fixed record-count folklore across schemas.
+- Keep related measurements together when it improves locality for actual
+  queries.
+- Flush deliberately where the binding requires it, then close the writer.
+
+## Read Path
+
+- Select only required measurements or columns.
+- Bound time ranges and push supported filters into the reader.
+- Stream or consume bounded batches instead of materializing an entire large
+  result set.
+- Separate metadata inspection from page decoding when the available tool or
+  API supports it.
+
+## Encoding and Compression
+
+- Start from the implementation defaults for the target version and language.
+- Match encodings to observed data distribution only after measuring: monotonic
+  integers, floating-point continuity, boolean/cardinality patterns, and text
+  repetition affect results differently.
+- Verify that the selected encoding is valid for the data type and implemented
+  by the chosen binding.
+- Measure compression ratio together with CPU cost and read/write latency; a
+  smaller file is not automatically the best operational result.
+
+## Benchmark Checklist
+
+1. Record the TsFile version, language binding, schema, encoding/compression,
+   batch size, and dataset characteristics.
+2. Warm up the runtime where applicable.
+3. Measure write throughput, read latency, peak memory, and output size.
+4. Validate file contents after each configuration.
+5. Change one important variable at a time and retain the baseline results.
diff --git a/skills/tsfile/references/python.md 
b/skills/tsfile/references/python.md
new file mode 100644
index 000000000..715ed6f58
--- /dev/null
+++ b/skills/tsfile/references/python.md
@@ -0,0 +1,85 @@
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+# Python SDK
+
+Use this reference only for Python binding work. The Python package depends on
+the C++ module in this source line; resolve the package version from
+`python/pyproject.toml`.
+
+## Table-Model Write
+
+```python
+from tsfile import (
+    ColumnCategory,
+    ColumnSchema,
+    TableSchema,
+    Tablet,
+    TSDataType,
+    TsFileTableWriter,
+)
+
+columns = [
+    ColumnSchema("device", TSDataType.STRING, ColumnCategory.TAG),
+    ColumnSchema("temperature", TSDataType.DOUBLE, ColumnCategory.FIELD),
+]
+schema = TableSchema("sensors", columns)
+tablet = Tablet(
+    schema.get_column_names(),
+    [column.get_data_type() for column in schema.get_columns()],
+    2,
+)
+tablet.add_timestamp(0, 1)
+tablet.add_value_by_name("device", 0, "d1")
+tablet.add_value_by_name("temperature", 0, 20.5)
+
+with TsFileTableWriter("data.tsfile", schema) as writer:
+    writer.write_table(tablet)
+```
+
+`ColumnSchema` exposes `get_column_name()` and `get_data_type()`; do not assume
+it has a public `name` attribute.
+
+## Table-Model Read
+
+```python
+from tsfile import TsFileReader
+
+with TsFileReader("data.tsfile") as reader:
+    schemas = reader.get_all_table_schemas()
+    schema = next(iter(schemas.values())) if isinstance(schemas, dict) else 
schemas[0]
+    table_name = schema.get_table_name()
+    with reader.query_table_by_row(
+        table_name, ["device", "temperature"], limit=10
+    ) as result:
+        frame = result.read_data_frame(max_row_num=10)
+```
+
+## Guidance
+
+- Current bindings expose `query_table` and `query_table_by_row`; do not reuse
+  older `get_table_names` or `read_table` examples without checking the target
+  version.
+- Schema collections may be lists or mappings depending on the binding layer;
+  normalize them before reusable iteration.
+- Use context managers for readers, writers, and results.
+- Use `python/examples/example.py` and `python/tests/` as executable API
+  documentation.
+- Verify from the repository root with
+  `./mvnw -P with-python clean verify`.
diff --git a/skills/tsfile/references/source-policy.md 
b/skills/tsfile/references/source-policy.md
new file mode 100644
index 000000000..2cfe4c08e
--- /dev/null
+++ b/skills/tsfile/references/source-policy.md
@@ -0,0 +1,95 @@
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+# TsFile Source Policy
+
+Apply this policy when choosing evidence, resolving versions, consulting the
+website, or updating an offline reference. Use `docs-map.yaml` as the URL
+registry; do not load it for ordinary offline API questions.
+
+## Resolve Scope First
+
+1. Treat the current skill baseline as the default. Override it only for an
+   explicit checkout, named release, or external project's dependency.
+2. For a checkout, run `scripts/resolve-version.sh`; pass `--root <checkout>`
+   for a different source tree. For an external binary/project without source,
+   inspect declared and locked dependencies before asking the user.
+3. If no checkout is discovered, use the returned `skill_baseline` versions;
+   do not infer or emulate an earlier TsFile API line.
+4. Treat `latest` website URLs as mutable V2.x navigation aliases, not release
+   identifiers. Use the download/release sources in `docs-map.yaml` to discover
+   published versions.
+
+## Authority Order
+
+Use the first source that matches the task and version:
+
+1. **Exact API or behavior in a checkout:** public source/header, tests, and
+   maintained examples from that same commit.
+2. **A named release:** its tag/source, release notes, and published artifacts;
+   then the matching official user-guide line.
+3. **Build requirements:** the target checkout's build files and CI profiles;
+   then release/download instructions.
+4. **Concepts and model terminology:** version-matched official documentation
+   or the corresponding local `docs/src/` source; use the offline skill archive
+   when neither needs to be refreshed.
+5. **Compatibility and operational guardrails:** tested local behavior and this
+   skill's references, clearly labeled with their target source line.
+
+Never let a remembered API, copied snippet, or mutable `latest` page override
+version-matched source. Website code linked to `develop` is evidence for that
+branch unless the same code is verified in the requested release.
+
+## Offline and Online Use
+
+- Work offline when the checkout plus one focused skill reference answers the
+  task. Cite the resolved version and local path in the result when freshness
+  matters.
+- Consult an official URL only when the user requests current/published
+  information, the target release is absent locally, a citation is required,
+  or local sources conflict or are incomplete.
+- Restrict authoritative online retrieval to `tsfile.apache.org`, Apache
+  distribution links reached from it, and `github.com/apache/tsfile`.
+- If network access is unavailable, continue with local sources and state the
+  last locally verified scope; do not claim that a mutable page is current.
+
+## Conflict Handling
+
+1. Report each conflicting version/source explicitly.
+2. Choose the source matching the requested artifact or checkout.
+3. Do not combine constructors, method names, defaults, or dependencies across
+   releases or language bindings.
+4. If the user does not identify another target, generate code for the current
+   skill baseline. Ask for a version only when the request explicitly targets
+   an external or different release but does not identify it.
+5. Treat ecosystem integration pages as leads that require dependency and
+   connector-version verification because they may evolve independently.
+
+## Deduplication and Updates
+
+- Keep stable workflows, source-selection rules, and verified incompatibilities
+  offline. Keep full tutorials, release inventories, and API catalogs on the
+  official site/source tree.
+- On a TsFile version change, recheck affected public APIs, examples, local
+  docs, mapped URLs, and cross-language smoke behavior before editing a
+  reference.
+- Update `docs-map.yaml:last_verified` only after checking its official URLs.
+  Do not record a discovered latest release as a permanent constant.
+- Replace obsolete offline facts instead of appending historical sections. Do
+  not carry prior-version fallback instructions in this skill.
diff --git a/skills/tsfile/scripts/build_tsfile.sh 
b/skills/tsfile/scripts/build_tsfile.sh
new file mode 100755
index 000000000..9477f9ead
--- /dev/null
+++ b/skills/tsfile/scripts/build_tsfile.sh
@@ -0,0 +1,218 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+TSFILE_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
+MVNW="${TSFILE_ROOT}/mvnw"
+
+cd "${TSFILE_ROOT}"
+
+command_exists() {
+    command -v "$1" >/dev/null 2>&1
+}
+
+check_java() {
+    if ! command_exists java; then
+        echo "Java not found; JDK 17 is required" >&2
+        return 1
+    fi
+
+    local specification_version major
+    specification_version="$({ java -XshowSettings:properties -version; } 2>&1 
\
+        | awk -F'= ' '/java.specification.version/ {print $2; exit}')"
+    if [[ "${specification_version}" == 1.* ]]; then
+        major="${specification_version#1.}"
+    else
+        major="${specification_version%%.*}"
+    fi
+    if [[ ! "${major}" =~ ^[0-9]+$ ]] || (( major < 17 )); then
+        echo "JDK 17 or newer is required; found 
${specification_version:-unknown}" >&2
+        return 1
+    fi
+    echo "Java ${specification_version}"
+}
+
+check_maven() {
+    if [[ ! -x "${MVNW}" ]]; then
+        echo "Maven wrapper not found: ${MVNW}" >&2
+        return 1
+    fi
+    "${MVNW}" --version | sed -n '1p'
+}
+
+check_cpp() {
+    local missing=()
+    local tool
+    for tool in cmake make c++ clang-format; do
+        if ! command_exists "${tool}"; then
+            missing+=("${tool}")
+        fi
+    done
+    if (( ${#missing[@]} > 0 )); then
+        echo "Missing C++ build tools: ${missing[*]}" >&2
+        return 1
+    fi
+    echo "C++ build tools found"
+}
+
+check_python() {
+    if ! command_exists python3; then
+        echo "Python 3.9 or newer is required" >&2
+        return 1
+    fi
+
+    local version major minor
+    version="$(python3 --version | awk '{print $2}')"
+    IFS='.' read -r major minor _ <<<"${version}"
+    if (( major < 3 || (major == 3 && minor < 9) )); then
+        echo "Python 3.9 or newer is required; found ${version}" >&2
+        return 1
+    fi
+    echo "Python ${version}"
+}
+
+build_tsfile() {
+    case "${1}" in
+        java)
+            "${MVNW}" -P with-java clean package -DskipTests
+            ;;
+        cpp)
+            check_cpp
+            "${MVNW}" -P with-cpp clean package -DskipTests
+            ;;
+        python)
+            check_cpp
+            check_python
+            "${MVNW}" -P with-python clean package -DskipTests
+            ;;
+        all)
+            check_cpp
+            check_python
+            "${MVNW}" -P with-java,with-python clean package -DskipTests
+            ;;
+        *)
+            echo "Unknown language: ${1}" >&2
+            return 1
+            ;;
+    esac
+}
+
+install_tsfile() {
+    case "${1}" in
+        java)
+            "${MVNW}" -P with-java clean install -DskipTests
+            ;;
+        all)
+            check_cpp
+            check_python
+            "${MVNW}" -P with-java,with-python clean install -DskipTests
+            ;;
+        *)
+            echo "Local install is supported for java or all" >&2
+            return 1
+            ;;
+    esac
+}
+
+test_tsfile() {
+    case "${1}" in
+        java)
+            "${MVNW}" -P with-java clean verify
+            ;;
+        cpp)
+            check_cpp
+            "${MVNW}" -P with-cpp clean verify
+            ;;
+        python)
+            check_cpp
+            check_python
+            "${MVNW}" -P with-python clean verify
+            ;;
+        all)
+            check_cpp
+            check_python
+            "${MVNW}" -P with-java,with-python clean verify
+            ;;
+        *)
+            echo "Unknown test target: ${1}" >&2
+            return 1
+            ;;
+    esac
+}
+
+show_usage() {
+    cat <<'EOF'
+TsFile multi-language build helper
+
+Usage: build_tsfile.sh <command> [language]
+
+Commands:
+  check
+  validate-assets
+  build <java|cpp|python|all>
+  install <java|all>
+  test <java|cpp|python|all>
+  clean
+
+Baseline:
+  Java: JDK 17
+  Maven: repository ./mvnw (Maven 3.6+)
+  C++: CMake 3.11+, C++11 compiler, make, clang-format, UUID headers where 
required
+  Python: Python 3.9+, C++ prerequisites
+EOF
+}
+
+case "${1:-}" in
+    check)
+        check_java
+        check_maven
+        check_cpp
+        check_python
+        ;;
+    validate-assets)
+        "${SCRIPT_DIR}/validate-assets.sh" --root "${TSFILE_ROOT}"
+        ;;
+    build)
+        [[ -n "${2:-}" ]] || { show_usage; exit 1; }
+        check_java
+        check_maven
+        build_tsfile "${2}"
+        ;;
+    install)
+        [[ -n "${2:-}" ]] || { show_usage; exit 1; }
+        check_java
+        check_maven
+        install_tsfile "${2}"
+        ;;
+    test)
+        [[ -n "${2:-}" ]] || { show_usage; exit 1; }
+        check_java
+        check_maven
+        test_tsfile "${2}"
+        ;;
+    clean)
+        check_maven
+        "${MVNW}" clean
+        ;;
+    *)
+        show_usage
+        exit 1
+        ;;
+esac
diff --git a/skills/tsfile/scripts/example.py b/skills/tsfile/scripts/example.py
new file mode 100755
index 000000000..528db8efd
--- /dev/null
+++ b/skills/tsfile/scripts/example.py
@@ -0,0 +1,315 @@
+#!/usr/bin/env python3
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+TsFile utility script for common operations
+
+This script provides utilities for working with TsFile format:
+- Demonstrating Python API CSV-to-TsFile conversion
+- Reading TsFile metadata
+- Basic validation operations
+"""
+
+import sys
+import pandas as pd
+import time
+from pathlib import Path
+
+
+def _table_schemas(reader):
+    schemas = reader.get_all_table_schemas()
+    if isinstance(schemas, dict):
+        return schemas
+    return {schema.get_table_name(): schema for schema in schemas or []}
+
+
+def _schema_columns(schema):
+    return [
+        {
+            "name": column.get_column_name(),
+            "type": str(column.get_data_type()),
+            "category": str(column.get_category()),
+        }
+        for column in schema.get_columns()
+    ]
+
+
+def _python_value(value, data_type, ts_data_type):
+    if data_type in (ts_data_type.INT32, ts_data_type.INT64):
+        return int(value)
+    if data_type in (ts_data_type.FLOAT, ts_data_type.DOUBLE):
+        return float(value)
+    if data_type == ts_data_type.BOOLEAN:
+        return bool(value)
+    return str(value)
+
+
+def csv_to_tsfile(
+    csv_path, tsfile_path, device_column="device", timestamp_column="timestamp"
+):
+    """
+    Convert CSV data to TsFile format
+
+    Args:
+        csv_path: Path to input CSV file
+        tsfile_path: Path to output TsFile
+        device_column: Name of device identifier column
+        timestamp_column: Name of timestamp column
+    """
+    try:
+        # Import TsFile after ensuring it's available
+        from tsfile import ColumnSchema, TableSchema, Tablet
+        from tsfile import TsFileTableWriter, TSDataType, ColumnCategory
+
+        # Read CSV
+        df = pd.read_csv(csv_path)
+        normalized_names = [str(column).lower() for column in df.columns]
+        if len(normalized_names) != len(set(normalized_names)):
+            raise ValueError("CSV columns must remain unique after 
lower-casing")
+        df.columns = normalized_names
+        device_column = device_column.lower()
+        timestamp_column = timestamp_column.lower()
+
+        if device_column not in df.columns:
+            raise ValueError(f"Device column '{device_column}' not found in 
CSV")
+
+        if timestamp_column not in df.columns:
+            raise ValueError(f"Timestamp column '{timestamp_column}' not found 
in CSV")
+
+        if df[[device_column, timestamp_column]].isnull().any().any():
+            raise ValueError(
+                "Device and timestamp columns must not contain null values"
+            )
+
+        if not pd.api.types.is_numeric_dtype(df[timestamp_column]):
+            df[timestamp_column] = pd.to_datetime(df[timestamp_column], 
errors="raise")
+
+        df = df.sort_values([device_column, timestamp_column], kind="stable")
+        if df.duplicated([device_column, timestamp_column]).any():
+            raise ValueError("Timestamps must be unique within each device")
+
+        # Infer column types and create schema.
+        columns = [ColumnSchema(device_column, TSDataType.STRING, 
ColumnCategory.TAG)]
+
+        for col in df.columns:
+            if col in [device_column, timestamp_column]:
+                continue
+
+            dtype = df[col].dtype
+            if pd.api.types.is_bool_dtype(dtype):
+                tsfile_type = TSDataType.BOOLEAN
+            elif pd.api.types.is_integer_dtype(dtype):
+                tsfile_type = TSDataType.INT64
+            elif pd.api.types.is_float_dtype(dtype):
+                tsfile_type = TSDataType.DOUBLE
+            else:
+                tsfile_type = TSDataType.STRING
+
+            columns.append(ColumnSchema(col, tsfile_type, 
ColumnCategory.FIELD))
+
+        table_schema = TableSchema("data", columns=columns)
+
+        # Write to TsFile
+        with TsFileTableWriter(tsfile_path, table_schema) as writer:
+            batch_size = 1000
+            total_rows = len(df)
+
+            for start_idx in range(0, total_rows, batch_size):
+                end_idx = min(start_idx + batch_size, total_rows)
+                batch_df = df.iloc[start_idx:end_idx]
+
+                tablet = Tablet(
+                    [column.get_column_name() for column in columns],
+                    [column.get_data_type() for column in columns],
+                    len(batch_df),
+                )
+
+                for i, (_, row) in enumerate(batch_df.iterrows()):
+                    # Convert timestamp to milliseconds
+                    if 
pd.api.types.is_datetime64_any_dtype(df[timestamp_column]):
+                        timestamp_ms = int(
+                            pd.to_datetime(row[timestamp_column]).timestamp() 
* 1000
+                        )
+                    else:
+                        timestamp_ms = int(row[timestamp_column])
+
+                    tablet.add_timestamp(i, timestamp_ms)
+
+                    for column in columns:
+                        column_name = column.get_column_name()
+                        value = row[column_name]
+                        if column_name == device_column:
+                            tablet.add_value_by_name(column_name, i, 
str(value))
+                        else:
+                            if pd.isna(value):
+                                continue  # Skip null values
+                            tablet.add_value_by_name(
+                                column_name,
+                                i,
+                                _python_value(
+                                    value, column.get_data_type(), TSDataType
+                                ),
+                            )
+
+                writer.write_table(tablet)
+
+        print(f"Successfully converted {csv_path} to {tsfile_path}")
+        print(f"Processed {total_rows} rows")
+
+    except ImportError:
+        print("Error: TsFile Python library not found.")
+        print(
+            "Build it from the repository root with: ./mvnw -P with-python 
clean verify"
+        )
+        sys.exit(1)
+    except Exception as e:
+        print(f"Error converting CSV to TsFile: {e}")
+        sys.exit(1)
+
+
+def inspect_tsfile(tsfile_path):
+    """
+    Inspect TsFile and display metadata information
+
+    Args:
+        tsfile_path: Path to TsFile
+    """
+    try:
+        from tsfile import TsFileReader
+
+        with TsFileReader(tsfile_path) as reader:
+            tables = _table_schemas(reader)
+            print(f"TsFile: {tsfile_path}")
+            print(f"Number of tables: {len(tables)}")
+
+            for table_name, schema in tables.items():
+                print(f"\nTable: {table_name}")
+                for column in _schema_columns(schema):
+                    print(
+                        f"  - {column['name']}: {column['type']} 
({column['category']})"
+                    )
+
+            print(
+                "\nNote: current packaged Python bindings expose 
query_table/query_table_by_row"
+            )
+            print(
+                "for row reads; this utility intentionally performs metadata 
inspection only."
+            )
+
+    except ImportError:
+        print("Error: TsFile Python library not found.")
+        print(
+            "Build it from the repository root with: ./mvnw -P with-python 
clean verify"
+        )
+        sys.exit(1)
+    except Exception as e:
+        print(f"Error reading TsFile: {e}")
+        sys.exit(1)
+
+
+def validate_tsfile(tsfile_path):
+    """
+    Validate TsFile format and check for common issues
+
+    Args:
+        tsfile_path: Path to TsFile
+    """
+    try:
+        from tsfile import TsFileReader
+
+        print(f"Validating TsFile: {tsfile_path}")
+
+        # Check if file exists
+        if not Path(tsfile_path).exists():
+            print("❌ File does not exist")
+            return False
+
+        # Try to read metadata without depending on row-read APIs.
+        start_time = time.time()
+        with TsFileReader(tsfile_path) as reader:
+            tables = _table_schemas(reader)
+
+            if not tables:
+                print("No tables found in TsFile")
+                return False
+
+        read_time = time.time() - start_time
+
+        print("TsFile metadata validation successful")
+        print(f"   Tables: {len(tables)}")
+        print(f"   Metadata read time: {read_time:.2f}s")
+
+        return True
+
+    except ImportError:
+        print("Error: TsFile Python library not found.")
+        print(
+            "Build it from the repository root with: ./mvnw -P with-python 
clean verify"
+        )
+        return False
+    except Exception as e:
+        print(f"❌ Validation failed: {e}")
+        return False
+
+
+def main():
+    if len(sys.argv) < 2:
+        print("TsFile Utility Script")
+        print("\nUsage:")
+        print(
+            "  python example.py csv2tsfile <csv_file> <tsfile_output> 
[device_col] [timestamp_col]"
+        )
+        print("  python example.py inspect <tsfile>")
+        print("  python example.py validate <tsfile>")
+        return
+
+    command = sys.argv[1]
+
+    if command == "csv2tsfile":
+        if len(sys.argv) < 4:
+            print(
+                "Usage: python example.py csv2tsfile <csv_file> 
<tsfile_output> [device_col] [timestamp_col]"
+            )
+            return
+
+        csv_path = sys.argv[2]
+        tsfile_path = sys.argv[3]
+        device_col = sys.argv[4] if len(sys.argv) > 4 else "device"
+        timestamp_col = sys.argv[5] if len(sys.argv) > 5 else "timestamp"
+
+        csv_to_tsfile(csv_path, tsfile_path, device_col, timestamp_col)
+
+    elif command == "inspect":
+        if len(sys.argv) < 3:
+            print("Usage: python example.py inspect <tsfile>")
+            return
+        inspect_tsfile(sys.argv[2])
+
+    elif command == "validate":
+        if len(sys.argv) < 3:
+            print("Usage: python example.py validate <tsfile>")
+            return
+        validate_tsfile(sys.argv[2])
+
+    else:
+        print(f"Unknown command: {command}")
+        print("Available commands: csv2tsfile, inspect, validate")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/skills/tsfile/scripts/resolve-version.sh 
b/skills/tsfile/scripts/resolve-version.sh
new file mode 100755
index 000000000..5a9d2d988
--- /dev/null
+++ b/skills/tsfile/scripts/resolve-version.sh
@@ -0,0 +1,240 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+DEFAULT_ROOT="${SCRIPT_DIR}/../../.."
+TSFILE_ROOT="${DEFAULT_ROOT}"
+EXPLICIT_ROOT="false"
+DOCS_MAP="${SCRIPT_DIR}/../references/docs-map.yaml"
+
+usage() {
+    cat <<'EOF'
+Resolve version metadata from an Apache TsFile source checkout or this skill's
+current-source baseline.
+
+Usage: resolve-version.sh [--root <checkout>]
+
+Output is line-oriented key=value data for Maven/Java, C++, Python, and Git.
+If no checkout is discovered, version fields come from the skill baseline in
+references/docs-map.yaml. An invalid explicit --root remains an error.
+EOF
+}
+
+fail() {
+    echo "resolve-version.sh: $*" >&2
+    exit 1
+}
+
+extract_skill_metadata() {
+    offline_reference_scope="current-source"
+    offline_reference_last_verified="not-recorded"
+
+    [[ -f "${DOCS_MAP}" ]] || fail "docs map not found: ${DOCS_MAP}"
+
+    parsed_last_verified="$(
+        awk '$1 == "last_verified:" { gsub(/\"/, "", $2); print $2; exit }' \
+            "${DOCS_MAP}"
+    )"
+    [[ -z "${parsed_last_verified}" ]] || \
+        offline_reference_last_verified="${parsed_last_verified}"
+
+    read_baseline_value() {
+        local key="$1"
+        awk -v key="${key}:" '
+            $1 == "skill_baseline:" { selected = 1; next }
+            selected && /^[^[:space:]]/ { exit }
+            selected && $1 == key {
+                value = $2
+                gsub(/"/, "", value)
+                print value
+                exit
+            }
+        ' "${DOCS_MAP}"
+    }
+
+    baseline_scope="$(read_baseline_value scope)"
+    baseline_source_ref="$(read_baseline_value source_ref)"
+    baseline_project_version="$(read_baseline_value maven_project_version)"
+    baseline_java_release="$(read_baseline_value java_release)"
+    baseline_cpp_version="$(read_baseline_value cpp_sdk_version)"
+    baseline_python_version="$(read_baseline_value python_package_version)"
+
+    [[ -n "${baseline_scope}" ]] || fail "skill baseline scope not found"
+    [[ -n "${baseline_source_ref}" ]] || fail "skill baseline source ref not 
found"
+    [[ -n "${baseline_project_version}" ]] || \
+        fail "skill baseline Maven version not found"
+    [[ -n "${baseline_java_release}" ]] || \
+        fail "skill baseline Java release not found"
+    [[ -n "${baseline_cpp_version}" ]] || \
+        fail "skill baseline C++ version not found"
+    [[ -n "${baseline_python_version}" ]] || \
+        fail "skill baseline Python version not found"
+    offline_reference_scope="${baseline_scope}"
+}
+
+print_result() {
+    printf 'version_source=%s\n' "${version_source}"
+    printf 'tsfile_root=%s\n' "${tsfile_root}"
+    printf 'maven_project_version=%s\n' "${project_version}"
+    printf 'java_artifact_version=%s\n' "${project_version}"
+    printf 'java_release=%s\n' "${java_release}"
+    printf 'cpp_sdk_version=%s\n' "${cpp_version}"
+    printf 'python_package_version=%s\n' "${python_version}"
+    printf 'git_commit=%s\n' "${git_commit}"
+    printf 'git_ref=%s\n' "${git_ref}"
+    printf 'git_dirty=%s\n' "${git_dirty}"
+    printf 'offline_reference_scope=%s\n' "${offline_reference_scope}"
+    printf 'offline_reference_last_verified=%s\n' \
+        "${offline_reference_last_verified}"
+}
+
+print_baseline_result() {
+    version_source="skill_baseline"
+    tsfile_root="not-present"
+    project_version="${baseline_project_version}"
+    java_release="${baseline_java_release}"
+    cpp_version="${baseline_cpp_version}"
+    python_version="${baseline_python_version}"
+    git_commit="not-recorded"
+    git_ref="${baseline_source_ref}"
+    git_dirty="not-applicable"
+    print_result
+}
+
+is_tsfile_checkout() {
+    local root="$1"
+    [[ -d "${root}" && -f "${root}/pom.xml" ]] || return 1
+    grep -q '<artifactId>tsfile-parent</artifactId>' "${root}/pom.xml"
+}
+
+extract_skill_metadata
+
+while (( $# > 0 )); do
+    case "$1" in
+        --root)
+            (( $# >= 2 )) || fail "--root requires a path"
+            TSFILE_ROOT="$2"
+            EXPLICIT_ROOT="true"
+            shift 2
+            ;;
+        -h|--help)
+            usage
+            exit 0
+            ;;
+        *)
+            fail "unknown argument: $1"
+            ;;
+    esac
+done
+
+if ! is_tsfile_checkout "${TSFILE_ROOT}"; then
+    if [[ "${EXPLICIT_ROOT}" == "true" ]]; then
+        [[ -d "${TSFILE_ROOT}" ]] || fail "checkout does not exist: 
${TSFILE_ROOT}"
+        [[ -f "${TSFILE_ROOT}/pom.xml" ]] || \
+            fail "root pom.xml not found: ${TSFILE_ROOT}/pom.xml"
+        fail "not an Apache TsFile source checkout: ${TSFILE_ROOT}"
+    fi
+    print_baseline_result
+    exit 0
+fi
+
+TSFILE_ROOT="$(cd "${TSFILE_ROOT}" && pwd)"
+POM="${TSFILE_ROOT}/pom.xml"
+
+extract_project_version() {
+    awk '
+        /<\/parent>/ { after_parent = 1; next }
+        after_parent && /<version>/ {
+            line = $0
+            sub(/^.*<version>/, "", line)
+            sub(/<\/version>.*$/, "", line)
+            print line
+            exit
+        }
+    ' "$1"
+}
+
+extract_xml_property() {
+    local property="$1"
+    awk -v property="${property}" '
+        index($0, "<" property ">") {
+            line = $0
+            sub("^.*<" property ">", "", line)
+            sub("</" property ">.*$", "", line)
+            print line
+            exit
+        }
+    ' "${POM}"
+}
+
+resolve_maven_property() {
+    local value="$1" property resolved
+    if [[ "${value}" =~ ^\$\{([A-Za-z0-9._-]+)\}$ ]]; then
+        property="${BASH_REMATCH[1]}"
+        resolved="$(extract_xml_property "${property}")"
+        [[ -n "${resolved}" ]] || fail "unresolved Maven version property: 
${value}"
+        value="${resolved}"
+    fi
+    printf '%s' "${value}"
+}
+
+project_version="$(extract_project_version "${POM}")"
+[[ -n "${project_version}" ]] || fail "project version not found in ${POM}"
+project_version="$(resolve_maven_property "${project_version}")"
+
+java_release="$(extract_xml_property maven.compiler.release)"
+[[ -n "${java_release}" ]] || fail "Java release not found in ${POM}"
+
+[[ -f "${TSFILE_ROOT}/cpp/CMakeLists.txt" ]] || \
+    fail "C++ metadata not found: ${TSFILE_ROOT}/cpp/CMakeLists.txt"
+cpp_version="$(
+    sed -n 
's/^[[:space:]]*set(TsFile_CPP_VERSION[[:space:]]*"\{0,1\}\([^"[:space:])]*\)"\{0,1\}[[:space:]]*).*/\1/p'
 \
+        "${TSFILE_ROOT}/cpp/CMakeLists.txt" | sed -n '1p'
+)"
+[[ -n "${cpp_version}" ]] || fail "C++ SDK version not found"
+
+[[ -f "${TSFILE_ROOT}/python/pyproject.toml" ]] || \
+    fail "Python metadata not found: ${TSFILE_ROOT}/python/pyproject.toml"
+python_version="$(
+    sed -n 's/^[[:space:]]*version[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' 
\
+        "${TSFILE_ROOT}/python/pyproject.toml" | sed -n '1p'
+)"
+[[ -n "${python_version}" ]] || fail "Python package version not found"
+
+git_commit="not-recorded"
+git_ref="not-recorded"
+git_dirty="not-applicable"
+if command -v git >/dev/null 2>&1 && git -C "${TSFILE_ROOT}" rev-parse 
--git-dir >/dev/null 2>&1; then
+    git_commit="$(git -C "${TSFILE_ROOT}" rev-parse HEAD)"
+    git_ref="$(git -C "${TSFILE_ROOT}" describe --tags --exact-match 
2>/dev/null || true)"
+    if [[ -z "${git_ref}" ]]; then
+        git_ref="$(git -C "${TSFILE_ROOT}" symbolic-ref --short HEAD 
2>/dev/null || true)"
+    fi
+    [[ -n "${git_ref}" ]] || git_ref="detached"
+    if [[ -n "$(git -C "${TSFILE_ROOT}" status --porcelain 2>/dev/null)" ]]; 
then
+        git_dirty="true"
+    else
+        git_dirty="false"
+    fi
+fi
+
+version_source="checkout_metadata"
+tsfile_root="${TSFILE_ROOT}"
+print_result
diff --git a/skills/tsfile/scripts/validate-assets.sh 
b/skills/tsfile/scripts/validate-assets.sh
new file mode 100755
index 000000000..860937e8b
--- /dev/null
+++ b/skills/tsfile/scripts/validate-assets.sh
@@ -0,0 +1,214 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+SKILL_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
+ASSETS_DIR="${SKILL_ROOT}/assets"
+DEFAULT_ROOT="${SCRIPT_DIR}/../../.."
+TSFILE_ROOT="${DEFAULT_ROOT}"
+EXPLICIT_ROOT="false"
+CHECKOUT_ROOT=""
+TSFILE_VERSION=""
+JAVA_JAR=""
+CPP_INCLUDE=""
+PYTHON_RUNTIME="false"
+
+usage() {
+    cat <<'EOF'
+Validate TsFile skill output templates.
+
+Usage: validate-assets.sh [--root <checkout>]
+                          [--tsfile-version <published-version>]
+                          [--java-jar <tsfile-jar>]
+                          [--cpp-include <include-directory>]
+                          [--python-runtime]
+
+The script always validates XML and Python syntax. It automatically uses a
+co-located TsFile checkout when available. Explicit Java artifacts or versions,
+C++ headers, and --python-runtime override the corresponding automatically
+discovered dependency. A Java version may be resolved through Maven; the script
+never guesses one.
+EOF
+}
+
+fail() {
+    echo "validate-assets.sh: $*" >&2
+    exit 1
+}
+
+command_required() {
+    command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
+}
+
+is_tsfile_checkout() {
+    local root="$1"
+    [[ -d "${root}" && -f "${root}/pom.xml" ]] || return 1
+    grep -q '<artifactId>tsfile-parent</artifactId>' "${root}/pom.xml"
+}
+
+while (( $# > 0 )); do
+    case "$1" in
+        --root)
+            (( $# >= 2 )) || fail "--root requires a path"
+            TSFILE_ROOT="$2"
+            EXPLICIT_ROOT="true"
+            shift 2
+            ;;
+        --tsfile-version)
+            (( $# >= 2 )) || fail "--tsfile-version requires a value"
+            TSFILE_VERSION="$2"
+            shift 2
+            ;;
+        --java-jar)
+            (( $# >= 2 )) || fail "--java-jar requires a file"
+            JAVA_JAR="$2"
+            shift 2
+            ;;
+        --cpp-include)
+            (( $# >= 2 )) || fail "--cpp-include requires a directory"
+            CPP_INCLUDE="$2"
+            shift 2
+            ;;
+        --python-runtime)
+            PYTHON_RUNTIME="true"
+            shift
+            ;;
+        -h|--help)
+            usage
+            exit 0
+            ;;
+        *)
+            fail "unknown argument: $1"
+            ;;
+    esac
+done
+
+if is_tsfile_checkout "${TSFILE_ROOT}"; then
+    CHECKOUT_ROOT="$(cd "${TSFILE_ROOT}" && pwd)"
+elif [[ "${EXPLICIT_ROOT}" == "true" ]]; then
+    [[ -d "${TSFILE_ROOT}" ]] || fail "checkout does not exist: ${TSFILE_ROOT}"
+    fail "not an Apache TsFile source checkout: ${TSFILE_ROOT}"
+fi
+
+command_required python3
+
+temp_dir="$(mktemp -d "${TMPDIR:-/tmp}/tsfile-assets.XXXXXX")"
+cleanup() {
+    case "${temp_dir}" in
+        "${TMPDIR:-/tmp}"/tsfile-assets.*) rm -rf -- "${temp_dir}" ;;
+        *) echo "validate-assets.sh: refusing to remove unexpected path: 
${temp_dir}" >&2 ;;
+    esac
+}
+trap cleanup EXIT
+
+python3 -c 'import sys, xml.etree.ElementTree as ET; ET.parse(sys.argv[1])' \
+    "${ASSETS_DIR}/pom.xml"
+PYTHONPYCACHEPREFIX="${temp_dir}/pycache" \
+    python3 -m py_compile "${ASSETS_DIR}/tsfile_example.py"
+
+pom_template="valid"
+python_template="syntax-valid"
+java_template="skipped-no-dependency"
+cpp_template="skipped-no-headers"
+
+compile_java_with_jar() {
+    local jar="$1"
+    command_required javac
+    mkdir -p "${temp_dir}/java-classes"
+    javac -cp "${jar}" -d "${temp_dir}/java-classes" \
+        "${ASSETS_DIR}/TsFileExample.java"
+    java_template="compiled"
+}
+
+compile_cpp_with_include() {
+    local include_dir="$1"
+    [[ -d "${include_dir}" ]] || fail "C++ include directory not found: 
${include_dir}"
+    command_required c++
+    c++ -std=c++11 -I "${include_dir}" -fsyntax-only \
+        "${ASSETS_DIR}/tsfile_example.cpp"
+    cpp_template="compiled"
+}
+
+run_python_template() {
+    local python_path="${1:-}"
+    cp "${ASSETS_DIR}/tsfile_example.py" "${temp_dir}/tsfile_example.py"
+    if [[ -n "${python_path}" ]]; then
+        (
+            cd "${temp_dir}"
+            PYTHONPATH="${python_path}" python3 tsfile_example.py >/dev/null
+        )
+    else
+        (
+            cd "${temp_dir}"
+            python3 tsfile_example.py >/dev/null
+        )
+    fi
+    python_template="compiled-and-ran"
+}
+
+if [[ -n "${TSFILE_VERSION}" && -n "${JAVA_JAR}" ]]; then
+    fail "use only one of --tsfile-version and --java-jar"
+elif [[ -n "${JAVA_JAR}" ]]; then
+    [[ -f "${JAVA_JAR}" ]] || fail "Java artifact not found: ${JAVA_JAR}"
+    compile_java_with_jar "${JAVA_JAR}"
+elif [[ -n "${TSFILE_VERSION}" ]]; then
+    command_required mvn
+    mkdir -p "${temp_dir}/java-template"
+    cp "${ASSETS_DIR}/pom.xml" "${ASSETS_DIR}/TsFileExample.java" \
+        "${temp_dir}/java-template/"
+    mvn -q -f "${temp_dir}/java-template/pom.xml" \
+        -Dtsfile.version="${TSFILE_VERSION}" compile
+    java_template="compiled"
+elif [[ -n "${CHECKOUT_ROOT}" ]]; then
+    version_output="$("${SCRIPT_DIR}/resolve-version.sh" --root 
"${CHECKOUT_ROOT}")"
+    java_version="$(
+        printf '%s\n' "${version_output}" | \
+            awk -F= '$1 == "java_artifact_version" { print $2; exit }'
+    )"
+    java_jar="${CHECKOUT_ROOT}/java/tsfile/target/tsfile-${java_version}.jar"
+    if [[ ! -f "${java_jar}" ]]; then
+        [[ -x "${CHECKOUT_ROOT}/mvnw" ]] || fail "Maven wrapper not found"
+        "${CHECKOUT_ROOT}/mvnw" -pl java/tsfile -am package -DskipTests
+    fi
+    [[ -f "${java_jar}" ]] || fail "Java artifact not found after build: 
${java_jar}"
+    compile_java_with_jar "${java_jar}"
+fi
+
+if [[ -n "${CPP_INCLUDE}" ]]; then
+    compile_cpp_with_include "${CPP_INCLUDE}"
+elif [[ -n "${CHECKOUT_ROOT}" ]]; then
+    compile_cpp_with_include "${CHECKOUT_ROOT}/cpp/src"
+fi
+
+if [[ "${PYTHON_RUNTIME}" == "true" ]]; then
+    run_python_template
+elif [[ -n "${CHECKOUT_ROOT}" ]]; then
+    if PYTHONPATH="${CHECKOUT_ROOT}/python" \
+        python3 -c 'import pandas, tsfile' >/dev/null 2>&1; then
+        run_python_template "${CHECKOUT_ROOT}/python"
+    else
+        python_template="syntax-valid-local-binding-not-built"
+    fi
+fi
+
+printf 'pom_template=%s\n' "${pom_template}"
+printf 'java_template=%s\n' "${java_template}"
+printf 'cpp_template=%s\n' "${cpp_template}"
+printf 'python_template=%s\n' "${python_template}"

Reply via email to