Don't expect the environment to have implicit things like tools in the PATH. Bazel builds are meant to be portable so you can invoke them remotely or share cache hits with your coworkers. Be explicit about getting tools you need as inputs, or using Bazel's toolchain feature to locate them on the disk.
Don't rely on the working directory to be next to the inputs. Bazel always sets the working directory in the root of the workspace, next to the WORKSPACE file. (Of course you can always chdir inside the process after Bazel starts it. In NodeJS, for example, you can do this with a
Don't try to write to the sources. The input directory will be in a read-only filesystem by default. For example Angular CLI runs the
ngcc program which tries to edit
package.json files in the inputs:
Don't try to write in a subdirectory of the sources either. Only write to the output directory.
Don't resolve symlinks of the inputs. Node programs often try to read symlinks because of a common pattern of linking build outputs of one package to be dependencies of another. Bazel creates an execroot (for build actions) and a runfiles root (for test/run) filled with symlinks to sources or other outputs. Resolving the symlinks causes non-hermeticity by finding undeclared input files, or causes logic bugs in the program if it compares a symlink target path and expects them to be the same.
Don't rely on stdin/stdout to communicate inputs and outputs. Bazel will sometimes use stdin for a protocol that communicates with the program, like worker mode or ibazel watch mode. It's possible to work around this with a genrule but that introduces a bash dependency.
Don't rely on accepting all the configuration over command line arguments. You will likely run into argv length limits. Consider accepting a configuration file or params file with the CLI flags written into it.
My earlier post about getting Nativescript tools to run under Bazel: medium.com/@Jakeherringbone/running-tools-u..