diff --git a/niflow_manager/cli/init.py b/niflow_manager/cli/init.py
index 05fc627..35d748b 100755
--- a/niflow_manager/cli/init.py
+++ b/niflow_manager/cli/init.py
@@ -5,7 +5,7 @@ import subprocess as sp
 import click
 
 from ..util.git import git_variables
-from ..util.fsutil import copytree
+from ..util.fsutil import copytree, CopyPolicy
 
 
 def normalize_path(name):
@@ -43,7 +43,9 @@ def normalize_path(name):
 
 @click.argument('name', type=click.Path(), default='.')
 @click.option('--language', help='Language for new niflow')
-def init(name, language):
+@click.option('--bids', 'bids_version', type=click.Choice(['1.0']),
+              help='Niflow intended as a BIDS App')
+def init(name, language, bids_version):
     path, full_name, organization, workflow = normalize_path(name)
 
     click.echo(f'Initializing workflow: {path.name} in {path.parent}')
@@ -75,3 +77,13 @@ def init(name, language):
             copytree(language_dir, path, mapping=mapping)
         except FileNotFoundError:
             raise ValueError(f"Unknown language: {language}")
+
+    if bids_version is not None:
+        if language is None:
+            raise ValueError("BIDS App templates are language-specific; please specify --language")
+        bids_app_dir = Path(pkgr_fn('niflow_manager',
+                                    f'data/templates/{language}-bidsapp-{bids_version}'))
+        try:
+            copytree(bids_app_dir, path, policy=CopyPolicy.OVERWRITE, mapping=mapping)
+        except FileNotFoundError:
+            raise ValueError(f"No BIDS App template for language: {language}")
diff --git a/niflow_manager/data/templates/python-bidsapp-1.0/package/setup.cfg b/niflow_manager/data/templates/python-bidsapp-1.0/package/setup.cfg
new file mode 100644
index 0000000..2d0f26e
--- /dev/null
+++ b/niflow_manager/data/templates/python-bidsapp-1.0/package/setup.cfg
@@ -0,0 +1,33 @@
+[metadata]
+name = {FULLNAME}
+version = attr: niflow.{ORGANIZATION}.{WORKFLOW}.__version__
+url = https://github.com/niflows/{FULLNAME}
+author = {USERNAME}
+author_email = {USEREMAIL}
+description = {FULLNAME} workflow package
+license = Apache License, 2.0
+classifiers =
+    Development Status :: 2 - Pre-Alpha
+    Environment :: Console
+    Intended Audience :: Developers
+    License :: OSI Approved :: Apache Software License
+    Operating System :: OS Independent
+    Programming Language :: Python :: 3
+    Topic :: Scientific/Engineering
+
+[options]
+packages = find:
+# Place any Python dependencies here
+install_requires = 
+    pybids
+# Uncomment the following line if your package should distribute any non-Python files
+# include_package_data = True
+
+[options.entry_points]
+console_scripts =
+    {FULLNAME} = niflow.{ORGANIZATION}.{WORKFLOW}.cli:main
+
+## If your workflow requires data to run, uncomment and update the following section:
+# [options.package_data]
+# {FULLNAME} =
+#     niflow/{ORGANIZATION}/{WORKFLOW}/data/*
diff --git a/niflow_manager/data/templates/python-bidsapp-1.0/package/{ORGANIZATION}/{WORKFLOW}/cli.py b/niflow_manager/data/templates/python-bidsapp-1.0/package/{ORGANIZATION}/{WORKFLOW}/cli.py
new file mode 100644
index 0000000..fb4f1ca
--- /dev/null
+++ b/niflow_manager/data/templates/python-bidsapp-1.0/package/{ORGANIZATION}/{WORKFLOW}/cli.py
@@ -0,0 +1,48 @@
+# This file provides a user-facing command-line interface (CLI) to your BIDS app
+from argparse import ArgumentParser
+from argparse import RawTextHelpFormatter
+import os.path as op
+from . import __version__
+from .workflow import init_{WORKFLOW}_wf
+
+
+# This parser includes the options that bids apps are required to accept
+# as well as a few additional parameters that are nice
+def get_parser():
+    """Build parser object"""
+    verstr = 'fitlins v{{}}'.format(__version__)
+
+    parser = ArgumentParser(description='Describe your BIDS app here',
+                            formatter_class=RawTextHelpFormatter)
+
+    # Arguments as specified by BIDS-Apps
+    # required, positional arguments
+    # IMPORTANT: they must go directly with the parser object
+    parser.add_argument('bids_dir', action='store', type=op.abspath,
+                        help='the root folder of a BIDS valid dataset (sub-XXXXX folders should '
+                             'be found at the top level in this folder).')
+    parser.add_argument('output_dir', action='store', type=op.abspath,
+                        help='the output path for the outcomes of preprocessing and visual '
+                             'reports')
+    parser.add_argument('analysis_level', choices=['run', 'session', 'participant', 'dataset'],
+                        help='processing stage to be runa (see BIDS-Apps specification).')
+
+    # optional arguments
+    parser.add_argument('-v', '--version', action='version', version=verstr)
+
+    g_bids = parser.add_argument_group('Options for filtering BIDS queries')
+    g_bids.add_argument('--participant-label', action='store', nargs='+', default=None,
+                        help='one or more participant identifiers (the sub- prefix can be '
+                             'removed)')
+    g_bids.add_argument('--derivative-label', action='store', type=str,
+                        help='execution label to append to derivative directory name')
+
+
+# The main function is what will be run when niflow-{ORGANIZATION}-{WORKFLOW} is called
+# Command-line arguments are available via the sys.argv list, though you should probably
+# use the parser object defined above as it already includes the required BIDS app
+# paramters. 
+def main():
+    opts = get_parser().parse_args()
+    wf = init_{WORKFLOW}_wf(opts)
+    wf.run()
diff --git a/niflow_manager/data/templates/python-bidsapp-1.0/package/{ORGANIZATION}/{WORKFLOW}/workflow.py b/niflow_manager/data/templates/python-bidsapp-1.0/package/{ORGANIZATION}/{WORKFLOW}/workflow.py
new file mode 100644
index 0000000..406035e
--- /dev/null
+++ b/niflow_manager/data/templates/python-bidsapp-1.0/package/{ORGANIZATION}/{WORKFLOW}/workflow.py
@@ -0,0 +1,30 @@
+# This file demonstrates a workflow-generating function, a particular convention for generating
+# nipype workflows. Others are possible.
+
+# Every workflow need pe.Workflow [0] and pe.Node [1], and most will need basic utility
+# interfaces [2].
+# [0] https://nipype.rtfd.io/en/latest/api/generated/nipype.pipeline.engine.workflows.html
+# [1] https://nipype.rtfd.io/en/latest/api/generated/nipype.pipeline.engine.nodes.html
+# [2] https://nipype.rtfd.io/en/latest/interfaces/generated/nipype.interfaces.utility/base.html
+from nipype.pipeline import engine as pe
+from nipype.interfaces import utility as niu
+
+def init_{WORKFLOW}_wf(opts, name='{WORKFLOW}_wf'):
+    wf = pe.Workflow(name=name)
+
+    # inputnode/outputnode can be thought of as the parameters and return values of a function
+    inputnode = pe.Node(niu.IdentityInterface(['in_file']), name='inputnode')
+    outputnode = pe.Node(niu.IdentityInterface(['out_file']), name='outputnode')
+
+    #
+    # The rest of the workflow should be defined here.
+    #
+
+    wf.connect([
+        ## Connect fields from one interface to another, e.g.,
+        # (inputnode, some_node_1, [('in_file', 'in_file')]),
+        # ...
+        # (some_node_n, outputnode, [('out_file', 'out_file')]),
+        ])
+
+    return wf

Add BIDS App option to nfm init
Talking to @satra, we should create a template for creating a BIDS app. For now, we'll focus on Python, in keeping with prior work.

I think it should probably be versioned, and we'll consider the paper (doi:[https://doi.org/10.1371/journal.pcbi.1005209](10.1371/journal.pcbi.1005209)) version 1.0, so my thought for syntax would be:

```Shell
nfm init --bids-app 1.0 --language python
```

cc @shotgunosine
diff --git a/niflow_manager/cli/tests/test_init.py b/niflow_manager/cli/tests/test_init.py
index a19c5ab..b3ba532 100644
--- a/niflow_manager/cli/tests/test_init.py
+++ b/niflow_manager/cli/tests/test_init.py
@@ -4,6 +4,8 @@ import pytest
 from click.testing import CliRunner
 from .. import main
 
+GIT_AUTHOR = 'Test Author'
+GIT_EMAIL = 'unreal3214@fake2182.tld'
 
 @pytest.mark.parametrize(
     "directory, organization, workflow, override, target, abort",
@@ -48,11 +50,17 @@ def test_init_path_selection(directory, organization, workflow, override, target
             assert (targ_path / '.git').exists()
 
 
-@pytest.mark.parametrize(
-    "author, email, gitconfig",
-    [('Test Author', 'unreal3214@fake2182.tld', os.devnull),
-     ('Test Author', 'unreal3214@fake2182.tld', 'tmp_gitconfig')])
-def test_init_python(author, email, gitconfig):
+def test_init_unknown_language():
+    runner = CliRunner()
+    args = ['init', 'niflow-org-wf', '--language', 'unsupportedlanguage']
+    with runner.isolated_filesystem():
+        result = runner.invoke(main, args, None)
+        assert result.exit_code != 0
+        assert "Unknown language" in result.exception.args[0]
+
+
+@pytest.mark.parametrize("gitconfig", [os.devnull, 'tmp_gitconfig'])
+def test_init_python(gitconfig):
     runner = CliRunner()
 
     args = ['init', 'niflow-org-wf', '--language', 'python']
@@ -61,10 +69,10 @@ def test_init_python(author, email, gitconfig):
         inputs = None
         if gitconfig != os.devnull:
             config_path = Path(gitconfig)
-            config_path.write_text(f'[user]\n\temail = {email}\n\tname = {author}')
+            config_path.write_text(f'[user]\n\temail = {GIT_EMAIL}\n\tname = {GIT_AUTHOR}')
             gitconfig = str(config_path.absolute())
         else:
-            inputs = '\n'.join([author, email])
+            inputs = '\n'.join([GIT_AUTHOR, GIT_EMAIL])
 
         result = runner.invoke(main, args, inputs, env={'GIT_CONFIG': gitconfig})
 
@@ -76,3 +84,42 @@ def test_init_python(author, email, gitconfig):
     else:
         assert 'Enter package author name: ' not in result.stdout
         assert 'Enter package author email: ' not in result.stdout
+
+
+def test_init_python_bidsapp():
+    runner = CliRunner()
+
+    args = ['init', 'niflow-org-bidsapp', '--language', 'python', '--bids', '1.0']
+
+    with runner.isolated_filesystem():
+        config_path = Path('tmp_gitconfig')
+        config_path.write_text(f'[user]\n\temail = {GIT_EMAIL}\n\tname = {GIT_AUTHOR}')
+        gitconfig = str(config_path.absolute())
+
+        result = runner.invoke(main, args, None, env={'GIT_CONFIG': gitconfig})
+
+        assert 'pybids' in Path('niflow-org-bidsapp/package/setup.cfg').read_text()
+
+    assert result.exit_code == 0
+
+
+@pytest.mark.parametrize("language", [None, "base"])
+def test_init_bidsapp(language):
+    runner = CliRunner()
+
+    args = ['init', 'niflow-org-bidsapp', '--bids', '1.0']
+    if language is not None:
+        args.extend(['--language', language])
+
+    with runner.isolated_filesystem():
+        config_path = Path('tmp_gitconfig')
+        config_path.write_text(f'[user]\n\temail = {GIT_EMAIL}\n\tname = {GIT_AUTHOR}')
+        gitconfig = str(config_path.absolute())
+
+        result = runner.invoke(main, args, None, env={'GIT_CONFIG': gitconfig})
+
+    assert result.exit_code != 0
+    if language is None:
+        assert 'language-specific' in result.exception.args[0]
+    else:
+        assert 'No BIDS App template' in result.exception.args[0]

pip install -e .[test]
parse_log_pytest
pytest
pytest pytest-cov codecov
apt-get update apt-get install -y gcc
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs @ file:///croot/attrs_1668696182826/work
certifi @ file:///croot/certifi_1671487769961/work/certifi
charset-normalizer==3.4.1
click==8.1.8
codecov==2.1.13
coverage==7.2.7
flit_core @ file:///opt/conda/conda-bld/flit-core_1644941570762/work/source/flit_core
idna==3.10
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1648562407465/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
-e git+https://github.com/niflows/niflow-manager.git@e3e915cd6c859e9adbbcc029c2318510599cbee5#egg=niflow_manager
packaging @ file:///croot/packaging_1671697413597/work
pluggy @ file:///tmp/build/80754af9/pluggy_1648042572264/work
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pytest==7.1.2
pytest-cov==4.1.0
requests==2.31.0
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
typing_extensions @ file:///croot/typing_extensions_1669924550328/work
urllib3==2.0.7
zipp @ file:///croot/zipp_1672387121353/work

name: niflow-manager
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=22.1.0=py37h06a4308_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - flit-core=3.6.0=pyhd3eb1b0_0
  - importlib-metadata=4.11.3=py37h06a4308_0
  - importlib_metadata=4.11.3=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=22.0=py37h06a4308_0
  - pip=22.3.1=py37h06a4308_0
  - pluggy=1.0.0=py37h06a4308_1
  - py=1.11.0=pyhd3eb1b0_0
  - pytest=7.1.2=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py37h06a4308_0
  - typing_extensions=4.4.0=py37h06a4308_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.11.0=py37h06a4308_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - charset-normalizer==3.4.1
      - click==8.1.8
      - codecov==2.1.13
      - coverage==7.2.7
      - idna==3.10
      - pytest-cov==4.1.0
      - requests==2.31.0
      - urllib3==2.0.7
prefix: /opt/conda/envs/niflow-manager

niflow_manager/cli/tests/test_init.py::test_init_python_bidsapp niflow_manager/cli/tests/test_init.py::test_init_bidsapp[None] niflow_manager/cli/tests/test_init.py::test_init_bidsapp[base]
niflow_manager/cli/tests/test_init.py::test_init_path_selection[None-org-wf-None-.-True] niflow_manager/cli/tests/test_init.py::test_init_path_selection[.-org-wf-None-.-True] niflow_manager/cli/tests/test_init.py::test_init_path_selection[None-org-wf-y-.-False] niflow_manager/cli/tests/test_init.py::test_init_path_selection[.-org-wf-y-.-False] niflow_manager/cli/tests/test_init.py::test_init_path_selection[niflow-org-wf-org-wf-None-niflow-org-wf-False] niflow_manager/cli/tests/test_init.py::test_init_path_selection[org-wf-org-wf-None-niflow-org-wf-False] niflow_manager/cli/tests/test_init.py::test_init_path_selection[ow-org-wf--niflow-org-wf-False] niflow_manager/cli/tests/test_init.py::test_init_path_selection[ow-org-wf-y-niflow-org-wf-False] niflow_manager/cli/tests/test_init.py::test_init_path_selection[ow-org-wf-n-niflow-ow-False] niflow_manager/cli/tests/test_init.py::test_init_unknown_language niflow_manager/cli/tests/test_init.py::test_init_python[/dev/null] niflow_manager/cli/tests/test_init.py::test_init_python[tmp_gitconfig]
niflow_manager/data/templates/python-bidsapp-1.0/package/{ORGANIZATION}/{WORKFLOW}/workflow.py niflow_manager/cli/init.py niflow_manager/data/templates/python-bidsapp-1.0/package/{ORGANIZATION}/{WORKFLOW}/cli.py niflow_manager/data/templates/python-bidsapp-1.0/package/setup.cfg
niflow_manager/data/templates/python-bidsapp-1.0/package/{ORGANIZATION}/{WORKFLOW}/workflow.py niflow_manager/cli/init.py niflow_manager/data/templates/python-bidsapp-1.0/package/{ORGANIZATION}/{WORKFLOW}/cli.py niflow_manager/data/templates/python-bidsapp-1.0/package/setup.cfg