Skip to content
Lucent
SEARCH LUCENT

Search guides, APIs, and examples.

GitHub

Very early and experimental. The language, the generated native code and every package API change without notice. Do not use Lucent in production.

CLI

Every lucent command and flag.

Every command finds the *.lucent.ts files under the project, skipping node_modules, ios, android and dot-directories, and the modules of the Lucent packages the app depends on. With no command, in a terminal, lucent opens lucent dev in a Lucent project and lucent init elsewhere.

CommandWhat it does
lucent buildCompile the project's modules and write the native package (.lucent/native); skipped when nothing changed
lucent checkType-check and validate every module without writing anything
lucent devRebuild on every change: a live dashboard of modules, platforms and problems (one line per build outside a terminal)
lucent doctorCheck the machine, the app and its builds: Node, React Native, Xcode, CocoaPods, Android, the JDK, Metro, versions
lucent initSet an app up for Lucent: the Metro config, the Expo plugin or the Gradle task, tsconfig.json, .gitignore, a first module
lucent new moduleScaffold a module in src/: shared, or with --ios / --android one module that branches on PLATFORM
lucent explainWhat a LUCENT diagnostic code means, and how to fix it (every code without one)
lucent benchTime the cases of your *.bench.ts files natively and as JavaScript, and show the speedup (needs a desktop Hermes)
lucent traceWrite the last build's steps and the runtime traces given as one Chrome trace (.lucent/trace.json), and how long each cause took
lucent cleanRemove the generated .lucent/ (the next build starts over)
lucent sdk searchFind SDK classes and members by name, with the import to copy (your imports and the SDK cache)
lucent sdk showPrint the declaration Lucent code sees for an SDK type or member: android.os.Vibrator, UIKit.UIDevice.current
lucent sdk prefetchExtract SDK bindings into the cache ahead of use (default: the lucent:* modules the project imports)
lucent sdk lockRecord the SDKs and SDK symbols the project uses in lucent-sdk.lock.json, for --frozen builds and sdk diff
lucent sdk diffWhat the installed SDKs change for the SDK symbols lucent-sdk.lock.json records: removed and changed members, before rebuilding
lucent sdk coveragePer SDK module, how far members get: discovered, representable, generated by the last build, exercised
FlagMeaning
--root <dir>Project directory (default: the current one)
--jsonMachine-readable output, for tools and CI
--helpShow help

Output is in color and animated only in a terminal. NO_COLOR, FORCE_COLOR, CI and TERM=dumb are respected. The tables on this page are generated from the command table lucent --help reads.

Compile the project's modules and write the native package (.lucent/native); skipped when nothing changed

FlagMeaning
--forceRebuild even when nothing changed
--platforms <list>Targets for platform code: ios, android, host (default: the SDKs installed)
--out <dir>Where to write the native package (default: .lucent/native)
--frozenFail unless the SDKs and SDK symbols are the ones lucent-sdk.lock.json records, with every target it lists (CI, releases)
terminal
◆ lucent 0.0.3
✓ SDK bindings CoreLocation · android.location · android.os cached
✓ Checked 2 modules 733 ms
✓ Generated C++ 2 changed 24 ms
✓ Native package .lucent/native
modules trip-tracker/location ios android
trip-tracker/trip shared
next rebuild the app (iOS: pod install first)
actions relink native dependencies ios LucentNative.podspec, cpp/generated/ios/m_location.mm +3 more
recompile native code ios, android cpp/generated/ios/m_location.mm, cpp/generated/android/m_location.cpp +2 more
  • When nothing changed since the last build, it says so and writes nothing, unless --force. Otherwise it rewrites only the files whose content changed.
  • next says what the app needs: a rebuild (after pod install when files were added or removed), a reload, or nothing. actions lists each thing the changes need, on which platforms, and the generated files behind it.
  • Actions come from what changed. A body edit recompiles native code, and new exports also reload JavaScript. A package's resources are repackaged, its libraries relinked. Info.plist entries, entitlements and manifest components need a reinstall. Other JavaScript needs nothing: Metro refreshes it.
  • A platform whose SDK isn't installed is skipped, with a warning. --platforms host builds stubs whose platform code throws, for tests.
  • On a problem, nothing is written and the exit code is 1.

Type-check and validate every module without writing anything

FlagMeaning
--frozenFail unless the SDKs and SDK symbols are the ones lucent-sdk.lock.json records, with every target it lists (CI, releases)

It reports problems as the diagnostics page shows them, and writes nothing. A pass is remembered, so checking an unchanged project takes a fraction of a second. Use it in CI.

Rebuild on every change: a live dashboard of modules, platforms and problems (one line per build outside a terminal)

FlagMeaning
--compactOne line per build instead of the dashboard (Metro runs it so)
terminal
[14:02:11] ✓ 2 modules 36 ms · rebuild the app · recompile native code (ios, android)
[14:03:40] ✗ 1 error
src/greet.lucent.ts:1:23 LUCENT2001 `any` has no native representation; give this value a concrete type
fix: use a concrete type, a union, or a generic parameter

In a terminal, it shows a dashboard of modules, platforms and problems. Its keys rebuild (r), clear the cache (c), run the doctor (d), open a problem in your editor (o) and quit (q). With --compact, or outside a terminal, it prints one line per build, as above: that's what withLucent runs next to Metro.

It watches the app and each Lucent package it links from outside it, such as a workspace package. It rebuilds when a file a build reads changes: a module, a package.json or lucent.json, or a native file a package lists. What builds write never triggers one, and a change during a build stops it before it writes anything.

Check the machine, the app and its builds: Node, React Native, Xcode, CocoaPods, Android, the JDK, Metro, versions

Each check passes, warns or fails, with its fix. The exit code is 1 when one fails. It doesn't load the compiler, so it answers even when the project doesn't build.

Set an app up for Lucent: the Metro config, the Expo plugin or the Gradle task, tsconfig.json, .gitignore, a first module

FlagMeaning
--yesApply every change without asking

It shows each change as a diff and applies the ones you confirm; --yes applies them all. Install Lucent lists the changes for Expo and bare apps. Running it again changes nothing.

Scaffold a module in src/: shared, or with --ios / --android one module that branches on PLATFORM

FlagMeaning
--iosImplement the iOS branch (without --android, the Android branch throws)
--androidImplement the Android branch (without --ios, the iOS branch throws)
--sharedOne module for every platform (the default)

What a LUCENT diagnostic code means, and how to fix it (every code without one)

Prints a code's entry from the diagnostics: why the rule exists, the fix, and a wrong and a right example. lucent explain 3006 works too.

Time the cases of your *.bench.ts files natively and as JavaScript, and show the speedup (needs a desktop Hermes)

src/path.bench.ts
import { pathLength, spiralLength } from "./path.lucent";
const points = Array.from({ length: 1000 }, (_, i) => ({
x: Math.cos(i / 10) * i,
y: Math.sin(i / 10) * i,
}));
export default {
objects: () => pathLength(points),
native: () => spiralLength(1000),
};

Each case runs as your module compiled to C++ and as the same TypeScript run as JavaScript, in a desktop Hermes. The results must match. It needs Hermes at ~/hermes, or HERMES_DIR; Design the boundary first shows its output.

Write the last build's steps and the runtime traces given as one Chrome trace (.lucent/trace.json), and how long each cause took

FlagMeaning
--runtime <files>Runtime traces to include, comma-separated (written with LUCENT_TRACE=<file>.json)
--out <file>Where to write it (default: .lucent/trace.json)

Remove the generated .lucent/ (the next build starts over)

FlagMeaning
--cacheAlso remove the SDK bindings cache

Find SDK classes and members by name, with the import to copy (your imports and the SDK cache)

Print the declaration Lucent code sees for an SDK type or member: android.os.Vibrator, UIKit.UIDevice.current

Extract SDK bindings into the cache ahead of use (default: the lucent:* modules the project imports)

FlagMeaning
--ios [<modules>]iOS modules, comma-separated; alone: every module
--android [<packages>]Android packages, comma-separated; alone: every package
--allEvery module of every installed SDK

Record the SDKs and SDK symbols the project uses in lucent-sdk.lock.json, for --frozen builds and sdk diff

FlagMeaning
--platforms <list>Targets to record: ios, android (default: every platform the project has code for, each needing its SDK)

What the installed SDKs change for the SDK symbols lucent-sdk.lock.json records: removed and changed members, before rebuilding

FlagMeaning
--allAlso the other members of the modules the project uses (the locked schemas must be in this machine's SDK cache)

Per SDK module, how far members get: discovered, representable, generated by the last build, exercised

FlagMeaning
--ios <modules>iOS modules, comma-separated
--android <packages>Android packages, comma-separated (p.* for a prefix)
--check <baseline>Fail when the unrepresentable share grows past a baseline JSON
--exercised <file>A JSON array of the symbol keys tests or probes ran (see --members)
--allEvery module of each SDK there is
--summary <file>Append a markdown summary of why members are left out (CI's step summary)
--membersList every member with its stage, key and reason
--viewsWith views on (LUCENT_VIEWS=fabric), list each view class's JSX attributes by rule