| name | tuyaopen/project-config |
| description | Create new TuyaOpen projects and platforms, manage build configurations, read and write Kconfig options non-interactively, update platform dependencies, and use tos.py subcommands. Use when the user mentions creating a project, tos.py new, saving or choosing a config, tos.py config set/get/list/diff, tos.py update, or general tos.py usage. 创建项目、新建工程、配置管理、保存配置、选择配置、读写配置项、更新依赖。 |
| license | Apache-2.0 |
| compatibility | ["TuyaOpen environment activated (export.sh / export.ps1 / export.bat)","TTY terminal required for interactive commands (tos.py new, config choice/menu/save)","tos.py config set/get/list/diff: newer SDKs only — detect with `tos.py config -h`, never from a version number"] |
TuyaOpen Project & Config Management
SDK root: All paths and commands in this skill are relative to the TuyaOpen SDK root ($OPEN_SDK_ROOT on Linux/macOS/PowerShell, %OPEN_SDK_ROOT% on Windows CMD). Activate the environment first — see skill tuyaopen/env-setup.
Docs: https://tuyaopen.ai/docs/tos-tools/tos-guide
Creating a New Project
All tos.py new subcommands are interactive (use input() / menu prompts). They require a TTY and cannot be used in non-interactive Agent/CI pipelines.
tos.py new project (interactive)
Creates a new application from a template in the current working directory.
cd apps/my_category
tos.py new project
tos.py new project --framework arduino
Flow:
- Prompts for project name (e.g.
my_app).
- Copies template from
tools/app_template/<framework>/ into <cwd>/<project_name>/.
- Fails if the directory already exists.
Templates:
| Framework | Entry file | Entry point |
|---|
base | src/tuya_app_main.c | user_main() — on Linux runs as main(), on MCU spawns a thread via tuya_app_main() |
arduino | src/tuya_app_main.cpp | Arduino-style setup() / loop() |
Generated project structure:
my_app/
├── CMakeLists.txt # collects src/, include/, links against tuyaos
└── src/
└── tuya_app_main.c
After creation — next steps:
cd my_app
- Select a config:
tos.py config choice (interactive), or manually create app_default.config (see skill tuyaopen/build for Kconfig format).
- Build:
tos.py build
A new project has no app_default.config — the build system will copy an empty template on first build, but you must configure a platform/board before a meaningful build succeeds.
tos.py new board (interactive)
Creates a new board BSP directory under boards/<platform>/.
Flow:
- Lists available platforms (T5AI, ESP32, LINUX, etc.) — select one.
- Prompts for new board name (e.g.
MY_CUSTOM_BOARD).
- Creates
boards/<platform>/<board_name>/ with template files (Kconfig, CMakeLists.txt, board_com_api.h, board source file).
- Automatically registers the board in
boards/<platform>/Kconfig so it appears in config choice.
- For ESP32, chip name defaults to
esp32s3; for other platforms, uses the platform name.
See skill tuyaopen/add-board for the full board adaptation guide.
Configuration Management
For detailed Kconfig editing guidance (dependency mechanisms, defconfig format, config pipeline), see skill tuyaopen/build.
Which config commands does this SDK have? — ask the SDK
tos.py config has two generations. Always ask the installed SDK what it supports; never infer it from a version number.
tos.py config -h
If -h lists… | Then |
|---|
only choice, menu, save | older generation — hand-edit app_default.config + tos.py clean -f |
also set, get, list, diff | newer generation — use them; also implies choice -l and save -n/-f |
Probe once, before planning the change, and commit to that branch. Do not run the new command and parse its failure.
If the environment isn't activated or you aren't inside a project directory (tos.py config requires both), check the source tree instead:
test -f "$OPEN_SDK_ROOT/tools/cli_command/util_kconfig.py"
Test-Path "$env:OPEN_SDK_ROOT/tools/cli_command/util_kconfig.py"
util_kconfig.py ships with the new subcommands, so its presence tracks them exactly.
Do not gate on tos.py version. It prints a git describe string such as v1.9.0-17-g13a1d0de — the tag is whatever release came before the checkout, so SDKs with and without these subcommands both report the same tag. Feature detection is the only reliable gate.
tos.py config choice (interactive)
tos.py config choice
tos.py config choice -d
tos.py config choice -l
Selects a pre-verified config. Writes to app_default.config. Triggers a full clean first.
Config lookup priority:
- Project's own
config/ directory (e.g. apps/tuya.ai/your_chat_bot/config/)
boards/<platform>/config/ global configs (shown when no project configs exist, or with -d)
Note: -d is an option of the choice subcommand (not the global --debug flag).
tos.py config menu (interactive)
tos.py config menu
Opens a terminal-based Kconfig editor. Triggers a full clean first. Best for fine-tuning options with complex dependencies — the editor resolves select / depends on automatically. See skill tuyaopen/build for the Kconfig Dependency Guide.
tos.py config save
tos.py config save
tos.py config save -n my_board
tos.py config save -n my_board -f
Copies the current app_default.config to the project's config/ directory as a named preset. Useful after customizing with config menu or config set.
Where -n is supported (check tos.py config save -h): it skips the prompt, an existing file is an error unless -f is given, and running without -n outside a TTY fails with a clear message instead of hanging.
Non-Interactive Config (Agent / CI)
1. Switching to a whole pre-verified config — works on every SDK:
tos.py config choice -c TUYA_T5AI_EVB
tos.py config choice -d -c TUYA_T5AI_EVB
This triggers a full clean, which is exactly what a board switch needs.
2. Changing individual options — depends on what tos.py config -h reported (see above).
set/get/list/diff present — use them. The CONFIG_ prefix is optional everywhere:
tos.py config get ENABLE_WIFI
tos.py config get -a ENABLE_LIBLVGL
tos.py config list -p MBEDTLS
tos.py config set ENABLE_LIBLVGL=y ENABLE_MBEDTLS_SSL_MAX_CONTENT_LEN=8192
tos.py config set -u ENABLE_LIBLVGL
tos.py config diff TUYA_T5AI_EVB
config set is dependency-aware and all-or-nothing: every token is validated before anything is written, so a failed batch writes nothing. It re-derives using.config and invalidates the generated build artifacts — no manual tos.py clean -f needed for an ordinary option change.
Full semantics, flags, and troubleshooting: references/CONFIG_CLI.md.
Not present — hand-edit app_default.config. See skill tuyaopen/build for format details and Kconfig dependency handling.
After hand-editing app_default.config, run tos.py clean -f before rebuilding. Unlike config choice / config menu / config set (which handle this automatically), a manual edit does not invalidate the build, so the stale .build/cache/using.config may be reused and your changes ignored. Run tos.py clean -f then tos.py build.
Hand-editing also bypasses kconfiglib: choice symbols are not made mutually exclusive and derived symbols (CONFIG_PLATFORM_CHOICE, CONFIG_CHIP_CHOICE) are not updated. Set exactly one platform and one board, and never set the derived symbols yourself.
Non-Interactive Project Creation (Agent / CI)
tos.py new is interactive and cannot be used in Agent/CI. Create the project manually by writing three files.
Required Directory Structure
<project_name>/
├── CMakeLists.txt
├── app_default.config
├── include/ # optional — create if you have shared headers
└── src/
└── tuya_app_main.c
The project can live under examples/ or apps/ — both are valid build locations.
Step 1: CMakeLists.txt
##
# @file CMakeLists.txt
# @brief
#/
set(APP_PATH ${CMAKE_CURRENT_LIST_DIR})
get_filename_component(APP_NAME ${APP_PATH} NAME)
aux_source_directory(${APP_PATH}/src APP_SRC)
set(APP_INC ${APP_PATH}/include)
########################################
# Target Configure
########################################
add_library(${EXAMPLE_LIB})
target_sources(${EXAMPLE_LIB}
PRIVATE
${APP_SRC}
)
target_include_directories(${EXAMPLE_LIB}
PRIVATE
${APP_INC}
)
This is the standard template from tools/app_template/base/CMakeLists.txt. It auto-collects all .c files under src/ — no need to list them individually.
Step 2: app_default.config
Select the target platform and board. Both a platform choice and a board choice are required.
Common platform + board pairs:
| Platform | Config lines | Target |
|---|
| LINUX / Ubuntu | CONFIG_BOARD_CHOICE_LINUX=y
CONFIG_BOARD_CHOICE_UBUNTU=y | Native x86/x64 ELF on Ubuntu/Debian |
| LINUX / Raspberry Pi | CONFIG_BOARD_CHOICE_LINUX=y
CONFIG_BOARD_CHOICE_RASPBERRY_PI=y | Native ARM ELF on RPi |
| T5AI | CONFIG_BOARD_CHOICE_T5AI=y | Tuya T5AI MCU |
| ESP32 | CONFIG_BOARD_CHOICE_ESP32=y | Espressif ESP32 series |
Example for LINUX (the only platform that can compile and run natively on the host):
CONFIG_BOARD_CHOICE_LINUX=y
CONFIG_BOARD_CHOICE_UBUNTU=y
Step 3: src/tuya_app_main.c
Entry source file must be named tuya_app_main.c (convention from the official template). It follows a dual-path entry pattern:
#include "tal_api.h"
#include "tkl_output.h"
static void user_main(void)
{
tal_log_init(TAL_LOG_LEVEL_DEBUG, 1024, (TAL_LOG_OUTPUT_CB)tkl_log_output);
PR_DEBUG("hello world\r\n");
while (1) {
tal_system_sleep(1000);
}
}
#if OPERATING_SYSTEM == SYSTEM_LINUX
void main(int argc, char *argv[])
{
user_main();
}
#else
static THREAD_HANDLE ty_app_thread = NULL;
static void tuya_app_thread(void *arg)
{
user_main();
tal_thread_delete(ty_app_thread);
ty_app_thread = NULL;
}
void tuya_app_main(void)
{
THREAD_CFG_T thrd_param = {0};
thrd_param.stackDepth = 1024 * 4;
thrd_param.priority = THREAD_PRIO_1;
thrd_param.thrdname = "tuya_app_main";
tal_thread_create_and_start(&ty_app_thread, NULL, NULL, tuya_app_thread, NULL, &thrd_param);
}
#endif
Key points:
user_main() contains all application logic
- On LINUX:
main() calls user_main() directly (native process)
- On MCU:
tuya_app_main() spawns a thread that calls user_main()
OPERATING_SYSTEM == SYSTEM_LINUX (value 100) is set automatically by the LINUX platform Kconfig
Step 4: Build and Run
cd <project_dir>
mkdir -p .cache && touch .cache/.dont_prompt_update_platform
tos.py build
./dist/<project>_<version>/<project>_<version>.elf
Updating Dependencies
tos.py update
Switches each platform submodule to its pinned commit ($OPEN_SDK_ROOT/platform/platform_config.yaml). Run after git pull.
tos.py Command Reference
See references/TOS_COMMANDS.md. For the non-interactive config subcommands in depth, see references/CONFIG_CLI.md.
Troubleshooting
| Symptom | Cause | Fix |
|---|
tos.py new hangs | Waiting for input() — interactive only | Use in a TTY terminal; cannot be automated |
Project exists error on new | Directory already exists | Choose a different name or delete the existing directory |
config menu arrow keys broken | Windows terminal compat | Use h/j/k/l; or switch between cmd/powershell |
could not lock config file | Stale ~/.gitconfig.lock | rm ~/.gitconfig.lock |
No configs shown in config choice | No config/ dir and no board configs for current platform | Create app_default.config manually or check platform setup |
Build fails after tos.py new | No config selected yet | Run tos.py config choice or create app_default.config |
Error: No such command 'set' | This SDK does not have the non-interactive config subcommands | Probe with tos.py config -h first; hand-edit app_default.config, then tos.py clean -f |
config set fails with a dependency reason | depends on / visibility blocks the symbol | tos.py config get -a NAME; enable the parent, or set both in one config set |
config save hangs or aborts in CI | Prompting for a name without a TTY | Pass -n NAME if config save -h lists it |
More config-specific troubleshooting: references/CONFIG_CLI.md.